summaryrefslogtreecommitdiff
path: root/src/dev/storage/ide_ctrl.cc
diff options
context:
space:
mode:
authorAndreas Sandberg <andreas.sandberg@arm.com>2015-12-10 10:35:23 +0000
committerAndreas Sandberg <andreas.sandberg@arm.com>2015-12-10 10:35:23 +0000
commit8ec5fc66321549ebda555e7c16ddaf158b021d2b (patch)
tree7053dc6b5b74e51efba35e24efcb203499c066b9 /src/dev/storage/ide_ctrl.cc
parent23c961a0fd97251ee7c760bc2ff2a011a417ad9b (diff)
downloadgem5-8ec5fc66321549ebda555e7c16ddaf158b021d2b.tar.xz
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
Diffstat (limited to 'src/dev/storage/ide_ctrl.cc')
-rw-r--r--src/dev/storage/ide_ctrl.cc650
1 files changed, 650 insertions, 0 deletions
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 <string>
+
+#include "cpu/intr_control.hh"
+#include "debug/IdeCtrl.hh"
+#include "dev/storage/ide_disk.hh"
+#include "mem/packet.hh"
+#include "mem/packet_access.hh"
+#include "params/IdeController.hh"
+#include "sim/byteswap.hh"
+
+// clang complains about std::set being overloaded with Packet::set if
+// we open up the entire namespace std
+using std::string;
+
+// Bus master IDE registers
+enum BMIRegOffset {
+ BMICommand = 0x0,
+ BMIStatus = 0x2,
+ BMIDescTablePtr = 0x4
+};
+
+// PCI config space registers
+enum ConfRegOffset {
+ PrimaryTiming = 0x40,
+ SecondaryTiming = 0x42,
+ DeviceTiming = 0x44,
+ UDMAControl = 0x48,
+ UDMATiming = 0x4A,
+ IDEConfig = 0x54
+};
+
+static const uint16_t timeRegWithDecodeEn = 0x8000;
+
+IdeController::Channel::Channel(
+ string newName, Addr _cmdSize, Addr _ctrlSize) :
+ _name(newName),
+ cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize),
+ master(NULL), slave(NULL), selected(NULL)
+{
+ memset(&bmiRegs, 0, sizeof(bmiRegs));
+ bmiRegs.status.dmaCap0 = 1;
+ bmiRegs.status.dmaCap1 = 1;
+}
+
+IdeController::Channel::~Channel()
+{
+}
+
+IdeController::IdeController(Params *p)
+ : PciDevice(p), primary(name() + ".primary", BARSize[0], BARSize[1]),
+ secondary(name() + ".secondary", BARSize[2], BARSize[3]),
+ bmiAddr(0), bmiSize(BARSize[4]),
+ primaryTiming(htole(timeRegWithDecodeEn)),
+ secondaryTiming(htole(timeRegWithDecodeEn)),
+ deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
+ ioEnabled(false), bmEnabled(false),
+ ioShift(p->io_shift), ctrlOffset(p->ctrl_offset)
+{
+ if (params()->disks.size() > 3)
+ panic("IDE controllers support a maximum of 4 devices attached!\n");
+
+ // Assign the disks to channels
+ int numDisks = params()->disks.size();
+ if (numDisks > 0)
+ primary.master = params()->disks[0];
+ if (numDisks > 1)
+ primary.slave = params()->disks[1];
+ if (numDisks > 2)
+ secondary.master = params()->disks[2];
+ if (numDisks > 3)
+ secondary.slave = params()->disks[3];
+
+ for (int i = 0; i < params()->disks.size(); i++) {
+ params()->disks[i]->setController(this);
+ }
+ primary.select(false);
+ secondary.select(false);
+
+ if ((BARAddrs[0] & ~BAR_IO_MASK) && (!legacyIO[0] || ioShift)) {
+ primary.cmdAddr = BARAddrs[0]; primary.cmdSize = BARSize[0];
+ primary.ctrlAddr = BARAddrs[1]; primary.ctrlSize = BARSize[1];
+ }
+ if ((BARAddrs[2] & ~BAR_IO_MASK) && (!legacyIO[2] || ioShift)) {
+ secondary.cmdAddr = BARAddrs[2]; secondary.cmdSize = BARSize[2];
+ secondary.ctrlAddr = BARAddrs[3]; secondary.ctrlSize = BARSize[3];
+ }
+
+ ioEnabled = (config.command & htole(PCI_CMD_IOSE));
+ bmEnabled = (config.command & htole(PCI_CMD_BME));
+}
+
+bool
+IdeController::isDiskSelected(IdeDisk *diskPtr)
+{
+ return (primary.selected == diskPtr || secondary.selected == diskPtr);
+}
+
+void
+IdeController::intrPost()
+{
+ primary.bmiRegs.status.intStatus = 1;
+ PciDevice::intrPost();
+}
+
+void
+IdeController::setDmaComplete(IdeDisk *disk)
+{
+ Channel *channel;
+ if (disk == primary.master || disk == primary.slave) {
+ channel = &primary;
+ } else if (disk == secondary.master || disk == secondary.slave) {
+ channel = &secondary;
+ } else {
+ panic("Unable to find disk based on pointer %#x\n", disk);
+ }
+
+ channel->bmiRegs.command.startStop = 0;
+ channel->bmiRegs.status.active = 0;
+ channel->bmiRegs.status.intStatus = 1;
+}
+
+Tick
+IdeController::readConfig(PacketPtr pkt)
+{
+ int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ return PciDevice::readConfig(pkt);
+ }
+
+ switch (pkt->getSize()) {
+ case sizeof(uint8_t):
+ switch (offset) {
+ case DeviceTiming:
+ pkt->set<uint8_t>(deviceTiming);
+ break;
+ case UDMAControl:
+ pkt->set<uint8_t>(udmaControl);
+ break;
+ case PrimaryTiming + 1:
+ pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8));
+ break;
+ case SecondaryTiming + 1:
+ pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8));
+ break;
+ case IDEConfig:
+ pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0));
+ break;
+ case IDEConfig + 1:
+ pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8));
+ break;
+ default:
+ panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
+ offset);
+ }
+ DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
+ (uint32_t)pkt->get<uint8_t>());
+ break;
+ case sizeof(uint16_t):
+ switch (offset) {
+ case UDMAControl:
+ pkt->set<uint16_t>(udmaControl);
+ break;
+ case PrimaryTiming:
+ pkt->set<uint16_t>(primaryTiming);
+ break;
+ case SecondaryTiming:
+ pkt->set<uint16_t>(secondaryTiming);
+ break;
+ case UDMATiming:
+ pkt->set<uint16_t>(udmaTiming);
+ break;
+ case IDEConfig:
+ pkt->set<uint16_t>(ideConfig);
+ break;
+ default:
+ panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
+ offset);
+ }
+ DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
+ (uint32_t)pkt->get<uint16_t>());
+ break;
+ case sizeof(uint32_t):
+ switch (offset) {
+ case PrimaryTiming:
+ pkt->set<uint32_t>(primaryTiming);
+ break;
+ case IDEConfig:
+ pkt->set<uint32_t>(ideConfig);
+ break;
+ default:
+ panic("No 32bit reads implemented for this device.");
+ }
+ DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
+ (uint32_t)pkt->get<uint32_t>());
+ break;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ pkt->makeAtomicResponse();
+ return configDelay;
+}
+
+
+Tick
+IdeController::writeConfig(PacketPtr pkt)
+{
+ int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
+ if (offset < PCI_DEVICE_SPECIFIC) {
+ PciDevice::writeConfig(pkt);
+ } else {
+ switch (pkt->getSize()) {
+ case sizeof(uint8_t):
+ switch (offset) {
+ case DeviceTiming:
+ deviceTiming = pkt->get<uint8_t>();
+ break;
+ case UDMAControl:
+ udmaControl = pkt->get<uint8_t>();
+ break;
+ case IDEConfig:
+ replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>());
+ break;
+ case IDEConfig + 1:
+ replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>());
+ break;
+ default:
+ panic("Invalid PCI configuration write "
+ "for size 1 offset: %#x!\n", offset);
+ }
+ DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
+ offset, (uint32_t)pkt->get<uint8_t>());
+ break;
+ case sizeof(uint16_t):
+ switch (offset) {
+ case UDMAControl:
+ udmaControl = pkt->get<uint16_t>();
+ break;
+ case PrimaryTiming:
+ primaryTiming = pkt->get<uint16_t>();
+ break;
+ case SecondaryTiming:
+ secondaryTiming = pkt->get<uint16_t>();
+ break;
+ case UDMATiming:
+ udmaTiming = pkt->get<uint16_t>();
+ break;
+ case IDEConfig:
+ ideConfig = pkt->get<uint16_t>();
+ break;
+ default:
+ panic("Invalid PCI configuration write "
+ "for size 2 offset: %#x!\n",
+ offset);
+ }
+ DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
+ offset, (uint32_t)pkt->get<uint16_t>());
+ break;
+ case sizeof(uint32_t):
+ switch (offset) {
+ case PrimaryTiming:
+ primaryTiming = pkt->get<uint32_t>();
+ break;
+ case IDEConfig:
+ ideConfig = pkt->get<uint32_t>();
+ break;
+ default:
+ panic("Write of unimplemented PCI config. register: %x\n", offset);
+ }
+ break;
+ default:
+ panic("invalid access size(?) for PCI configspace!\n");
+ }
+ pkt->makeAtomicResponse();
+ }
+
+ /* Trap command register writes and enable IO/BM as appropriate as well as
+ * BARs. */
+ switch(offset) {
+ case PCI0_BASE_ADDR0:
+ if (BARAddrs[0] != 0)
+ primary.cmdAddr = BARAddrs[0];
+ break;
+
+ case PCI0_BASE_ADDR1:
+ if (BARAddrs[1] != 0)
+ primary.ctrlAddr = BARAddrs[1];
+ break;
+
+ case PCI0_BASE_ADDR2:
+ if (BARAddrs[2] != 0)
+ secondary.cmdAddr = BARAddrs[2];
+ break;
+
+ case PCI0_BASE_ADDR3:
+ if (BARAddrs[3] != 0)
+ secondary.ctrlAddr = BARAddrs[3];
+ break;
+
+ case PCI0_BASE_ADDR4:
+ if (BARAddrs[4] != 0)
+ bmiAddr = BARAddrs[4];
+ break;
+
+ case PCI_COMMAND:
+ DPRINTF(IdeCtrl, "Writing to PCI Command val: %#x\n", config.command);
+ ioEnabled = (config.command & htole(PCI_CMD_IOSE));
+ bmEnabled = (config.command & htole(PCI_CMD_BME));
+ break;
+ }
+ return configDelay;
+}
+
+void
+IdeController::Channel::accessCommand(Addr offset,
+ int size, uint8_t *data, bool read)
+{
+ const Addr SelectOffset = 6;
+ const uint8_t SelectDevBit = 0x10;
+
+ if (!read && offset == SelectOffset)
+ select(*data & SelectDevBit);
+
+ if (selected == NULL) {
+ assert(size == sizeof(uint8_t));
+ *data = 0;
+ } else if (read) {
+ selected->readCommand(offset, size, data);
+ } else {
+ selected->writeCommand(offset, size, data);
+ }
+}
+
+void
+IdeController::Channel::accessControl(Addr offset,
+ int size, uint8_t *data, bool read)
+{
+ if (selected == NULL) {
+ assert(size == sizeof(uint8_t));
+ *data = 0;
+ } else if (read) {
+ selected->readControl(offset, size, data);
+ } else {
+ selected->writeControl(offset, size, data);
+ }
+}
+
+void
+IdeController::Channel::accessBMI(Addr offset,
+ int size, uint8_t *data, bool read)
+{
+ assert(offset + size <= sizeof(BMIRegs));
+ if (read) {
+ memcpy(data, (uint8_t *)&bmiRegs + offset, size);
+ } else {
+ switch (offset) {
+ case BMICommand:
+ {
+ if (size != sizeof(uint8_t))
+ panic("Invalid BMIC write size: %x\n", size);
+
+ BMICommandReg oldVal = bmiRegs.command;
+ BMICommandReg newVal = *data;
+
+ // if a DMA transfer is in progress, R/W control cannot change
+ if (oldVal.startStop && oldVal.rw != newVal.rw)
+ oldVal.rw = newVal.rw;
+
+ if (oldVal.startStop != newVal.startStop) {
+ if (selected == NULL)
+ panic("DMA start for disk which does not exist\n");
+
+ if (oldVal.startStop) {
+ DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
+ bmiRegs.status.active = 0;
+
+ selected->abortDma();
+ } else {
+ DPRINTF(IdeCtrl, "Starting DMA transfer\n");
+ bmiRegs.status.active = 1;
+
+ selected->startDma(letoh(bmiRegs.bmidtp));
+ }
+ }
+
+ bmiRegs.command = newVal;
+ }
+ break;
+ case BMIStatus:
+ {
+ if (size != sizeof(uint8_t))
+ panic("Invalid BMIS write size: %x\n", size);
+
+ BMIStatusReg oldVal = bmiRegs.status;
+ BMIStatusReg newVal = *data;
+
+ // the BMIDEA bit is read only
+ newVal.active = oldVal.active;
+
+ // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
+ if ((oldVal.intStatus == 1) && (newVal.intStatus == 1)) {
+ newVal.intStatus = 0; // clear the interrupt?
+ } else {
+ // Assigning two bitunion fields to each other does not
+ // work as intended, so we need to use this temporary variable
+ // to get around the bug.
+ uint8_t tmp = oldVal.intStatus;
+ newVal.intStatus = tmp;
+ }
+ if ((oldVal.dmaError == 1) && (newVal.dmaError == 1)) {
+ newVal.dmaError = 0;
+ } else {
+ uint8_t tmp = oldVal.dmaError;
+ newVal.dmaError = tmp;
+ }
+
+ bmiRegs.status = newVal;
+ }
+ break;
+ case BMIDescTablePtr:
+ if (size != sizeof(uint32_t))
+ panic("Invalid BMIDTP write size: %x\n", size);
+ bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3);
+ break;
+ default:
+ if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
+ size != sizeof(uint32_t))
+ panic("IDE controller write of invalid write size: %x\n", size);
+ memcpy((uint8_t *)&bmiRegs + offset, data, size);
+ }
+ }
+}
+
+void
+IdeController::dispatchAccess(PacketPtr pkt, bool read)
+{
+ if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
+ panic("Bad IDE read size: %d\n", pkt->getSize());
+
+ if (!ioEnabled) {
+ pkt->makeAtomicResponse();
+ DPRINTF(IdeCtrl, "io not enabled\n");
+ return;
+ }
+
+ Addr addr = pkt->getAddr();
+ int size = pkt->getSize();
+ uint8_t *dataPtr = pkt->getPtr<uint8_t>();
+
+ if (addr >= primary.cmdAddr &&
+ addr < (primary.cmdAddr + primary.cmdSize)) {
+ addr -= primary.cmdAddr;
+ // linux may have shifted the address by ioShift,
+ // here we shift it back, similarly for ctrlOffset.
+ addr >>= ioShift;
+ primary.accessCommand(addr, size, dataPtr, read);
+ } else if (addr >= primary.ctrlAddr &&
+ addr < (primary.ctrlAddr + primary.ctrlSize)) {
+ addr -= primary.ctrlAddr;
+ addr += ctrlOffset;
+ primary.accessControl(addr, size, dataPtr, read);
+ } else if (addr >= secondary.cmdAddr &&
+ addr < (secondary.cmdAddr + secondary.cmdSize)) {
+ addr -= secondary.cmdAddr;
+ secondary.accessCommand(addr, size, dataPtr, read);
+ } else if (addr >= secondary.ctrlAddr &&
+ addr < (secondary.ctrlAddr + secondary.ctrlSize)) {
+ addr -= secondary.ctrlAddr;
+ secondary.accessControl(addr, size, dataPtr, read);
+ } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) {
+ if (!read && !bmEnabled)
+ return;
+ addr -= bmiAddr;
+ if (addr < sizeof(Channel::BMIRegs)) {
+ primary.accessBMI(addr, size, dataPtr, read);
+ } else {
+ addr -= sizeof(Channel::BMIRegs);
+ secondary.accessBMI(addr, size, dataPtr, read);
+ }
+ } else {
+ panic("IDE controller access to invalid address: %#x\n", addr);
+ }
+
+#ifndef NDEBUG
+ uint32_t data;
+ if (pkt->getSize() == 1)
+ data = pkt->get<uint8_t>();
+ else if (pkt->getSize() == 2)
+ data = pkt->get<uint16_t>();
+ else
+ data = pkt->get<uint32_t>();
+ DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
+ read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
+#endif
+
+ pkt->makeAtomicResponse();
+}
+
+Tick
+IdeController::read(PacketPtr pkt)
+{
+ dispatchAccess(pkt, true);
+ return pioDelay;
+}
+
+Tick
+IdeController::write(PacketPtr pkt)
+{
+ dispatchAccess(pkt, false);
+ return pioDelay;
+}
+
+void
+IdeController::serialize(CheckpointOut &cp) const
+{
+ // Serialize the PciDevice base class
+ PciDevice::serialize(cp);
+
+ // Serialize channels
+ primary.serialize("primary", cp);
+ secondary.serialize("secondary", cp);
+
+ // Serialize config registers
+ SERIALIZE_SCALAR(primaryTiming);
+ SERIALIZE_SCALAR(secondaryTiming);
+ SERIALIZE_SCALAR(deviceTiming);
+ SERIALIZE_SCALAR(udmaControl);
+ SERIALIZE_SCALAR(udmaTiming);
+ SERIALIZE_SCALAR(ideConfig);
+
+ // Serialize internal state
+ SERIALIZE_SCALAR(ioEnabled);
+ SERIALIZE_SCALAR(bmEnabled);
+ SERIALIZE_SCALAR(bmiAddr);
+ SERIALIZE_SCALAR(bmiSize);
+}
+
+void
+IdeController::Channel::serialize(const std::string &base,
+ CheckpointOut &cp) const
+{
+ paramOut(cp, base + ".cmdAddr", cmdAddr);
+ paramOut(cp, base + ".cmdSize", cmdSize);
+ paramOut(cp, base + ".ctrlAddr", ctrlAddr);
+ paramOut(cp, base + ".ctrlSize", ctrlSize);
+ uint8_t command = bmiRegs.command;
+ paramOut(cp, base + ".bmiRegs.command", command);
+ paramOut(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
+ uint8_t status = bmiRegs.status;
+ paramOut(cp, base + ".bmiRegs.status", status);
+ paramOut(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
+ paramOut(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
+ paramOut(cp, base + ".selectBit", selectBit);
+}
+
+void
+IdeController::unserialize(CheckpointIn &cp)
+{
+ // Unserialize the PciDevice base class
+ PciDevice::unserialize(cp);
+
+ // Unserialize channels
+ primary.unserialize("primary", cp);
+ secondary.unserialize("secondary", cp);
+
+ // Unserialize config registers
+ UNSERIALIZE_SCALAR(primaryTiming);
+ UNSERIALIZE_SCALAR(secondaryTiming);
+ UNSERIALIZE_SCALAR(deviceTiming);
+ UNSERIALIZE_SCALAR(udmaControl);
+ UNSERIALIZE_SCALAR(udmaTiming);
+ UNSERIALIZE_SCALAR(ideConfig);
+
+ // Unserialize internal state
+ UNSERIALIZE_SCALAR(ioEnabled);
+ UNSERIALIZE_SCALAR(bmEnabled);
+ UNSERIALIZE_SCALAR(bmiAddr);
+ UNSERIALIZE_SCALAR(bmiSize);
+}
+
+void
+IdeController::Channel::unserialize(const std::string &base, CheckpointIn &cp)
+{
+ paramIn(cp, base + ".cmdAddr", cmdAddr);
+ paramIn(cp, base + ".cmdSize", cmdSize);
+ paramIn(cp, base + ".ctrlAddr", ctrlAddr);
+ paramIn(cp, base + ".ctrlSize", ctrlSize);
+ uint8_t command;
+ paramIn(cp, base +".bmiRegs.command", command);
+ bmiRegs.command = command;
+ paramIn(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
+ uint8_t status;
+ paramIn(cp, base + ".bmiRegs.status", status);
+ bmiRegs.status = status;
+ paramIn(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
+ paramIn(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
+ paramIn(cp, base + ".selectBit", selectBit);
+ select(selectBit);
+}
+
+IdeController *
+IdeControllerParams::create()
+{
+ return new IdeController(this);
+}