ide_ctrl.cc revision 5775
14780SN/A/*
24780SN/A * Copyright (c) 2004-2005 The Regents of The University of Michigan
34780SN/A * All rights reserved.
44780SN/A *
54780SN/A * Redistribution and use in source and binary forms, with or without
64780SN/A * modification, are permitted provided that the following conditions are
74780SN/A * met: redistributions of source code must retain the above copyright
84780SN/A * notice, this list of conditions and the following disclaimer;
94780SN/A * redistributions in binary form must reproduce the above copyright
104780SN/A * notice, this list of conditions and the following disclaimer in the
114780SN/A * documentation and/or other materials provided with the distribution;
124780SN/A * neither the name of the copyright holders nor the names of its
134780SN/A * contributors may be used to endorse or promote products derived from
144780SN/A * this software without specific prior written permission.
154780SN/A *
164780SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
174780SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
184780SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
194780SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
204780SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
214780SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
224780SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
234780SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
244780SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
254780SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
264780SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
274780SN/A *
284780SN/A * Authors: Andrew Schultz
294780SN/A *          Ali Saidi
304780SN/A *          Miguel Serrano
314780SN/A */
324780SN/A
338229Snate@binkert.org#include <string>
348229Snate@binkert.org
358229Snate@binkert.org#include "base/trace.hh"
368229Snate@binkert.org#include "cpu/intr_control.hh"
378229Snate@binkert.org#include "dev/ide_ctrl.hh"
384780SN/A#include "dev/ide_disk.hh"
398113Sgblack@eecs.umich.edu#include "mem/packet.hh"
404780SN/A#include "mem/packet_access.hh"
414780SN/A#include "params/IdeController.hh"
424780SN/A#include "sim/byteswap.hh"
438108SN/A
448108SN/Ausing namespace std;
454780SN/A
465049SN/A// Bus master IDE registers
475049SN/Aenum BMIRegOffset {
488108SN/A    BMICommand = 0x0,
495049SN/A    BMIStatus = 0x2,
508108SN/A    BMIDescTablePtr = 0x4
514780SN/A};
524780SN/A
534780SN/A// PCI config space registers
544780SN/Aenum ConfRegOffset {
554780SN/A    PrimaryTiming = 0x40,
565049SN/A    SecondaryTiming = 0x42,
578108SN/A    DeviceTiming = 0x44,
584780SN/A    UDMAControl = 0x48,
594780SN/A    UDMATiming = 0x4A,
604780SN/A    IDEConfig = 0x54
614780SN/A};
628108SN/A
635049SN/Astatic const uint16_t timeRegWithDecodeEn = 0x8000;
648108SN/A
655049SN/AIdeController::Channel::Channel(
665049SN/A        string newName, Addr _cmdSize, Addr _ctrlSize) :
675049SN/A    _name(newName),
685049SN/A    cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize),
695049SN/A    master(NULL), slave(NULL), selected(NULL)
708108SN/A{
715049SN/A    memset(&bmiRegs, 0, sizeof(bmiRegs));
728108SN/A    bmiRegs.status.dmaCap0 = 1;
735049SN/A    bmiRegs.status.dmaCap1 = 1;
745049SN/A}
755049SN/A
765049SN/AIdeController::Channel::~Channel()
775049SN/A{
784780SN/A    delete master;
794780SN/A    delete slave;
804780SN/A}
818108SN/A
828108SN/AIdeController::IdeController(Params *p)
835049SN/A    : PciDev(p), primary(name() + ".primary", BARSize[0], BARSize[1]),
844780SN/A    secondary(name() + ".secondary", BARSize[2], BARSize[3]),
855049SN/A    bmiAddr(0), bmiSize(BARSize[4]),
868108SN/A    primaryTiming(htole(timeRegWithDecodeEn)),
878108SN/A    secondaryTiming(htole(timeRegWithDecodeEn)),
888108SN/A    deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
898108SN/A    ioEnabled(false), bmEnabled(false)
908108SN/A{
918108SN/A    if (params()->disks.size() > 3)
928108SN/A        panic("IDE controllers support a maximum of 4 devices attached!\n");
938108SN/A
948108SN/A    // Assign the disks to channels
958108SN/A    int numDisks = params()->disks.size();
968108SN/A    if (numDisks > 0)
978108SN/A        primary.master = params()->disks[0];
988108SN/A    if (numDisks > 1)
998108SN/A        primary.slave = params()->disks[1];
1008108SN/A    if (numDisks > 2)
1018108SN/A        secondary.master = params()->disks[2];
1028108SN/A    if (numDisks > 3)
1038108SN/A        secondary.slave = params()->disks[3];
1048108SN/A
1058108SN/A    for (int i = 0; i < params()->disks.size(); i++) {
1068108SN/A        params()->disks[i]->setController(this);
1078108SN/A    }
1088108SN/A    primary.select(false);
1098108SN/A    secondary.select(false);
1108108SN/A}
1118108SN/A
1128108SN/Abool
1138108SN/AIdeController::isDiskSelected(IdeDisk *diskPtr)
1148108SN/A{
1158108SN/A    return (primary.selected == diskPtr || secondary.selected == diskPtr);
1168108SN/A}
1178108SN/A
1188108SN/Avoid
1198108SN/AIdeController::intrPost()
1208108SN/A{
1218108SN/A    primary.bmiRegs.status.intStatus = 1;
1228108SN/A    PciDev::intrPost();
1238108SN/A}
1248108SN/A
1258108SN/Avoid
1268108SN/AIdeController::setDmaComplete(IdeDisk *disk)
1278108SN/A{
1288108SN/A    Channel *channel;
1298108SN/A    if (disk == primary.master || disk == primary.slave) {
1308108SN/A        channel = &primary;
1318108SN/A    } else if (disk == secondary.master || disk == secondary.slave) {
1328108SN/A        channel = &secondary;
1338108SN/A    } else {
1348108SN/A        panic("Unable to find disk based on pointer %#x\n", disk);
1358108SN/A    }
1368108SN/A
1378108SN/A    channel->bmiRegs.command.startStop = 0;
1388108SN/A    channel->bmiRegs.status.active = 0;
1398108SN/A    channel->bmiRegs.status.intStatus = 1;
1408108SN/A}
1418108SN/A
1428108SN/ATick
1438108SN/AIdeController::readConfig(PacketPtr pkt)
1448108SN/A{
1458108SN/A    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
1468108SN/A    if (offset < PCI_DEVICE_SPECIFIC) {
1478108SN/A        return PciDev::readConfig(pkt);
1488108SN/A    }
1498108SN/A
1508108SN/A    pkt->allocate();
1518108SN/A
1528108SN/A    switch (pkt->getSize()) {
1538108SN/A      case sizeof(uint8_t):
1548108SN/A        switch (offset) {
1558108SN/A          case DeviceTiming:
1568108SN/A            pkt->set<uint8_t>(deviceTiming);
1578108SN/A            break;
1588108SN/A          case UDMAControl:
1598108SN/A            pkt->set<uint8_t>(udmaControl);
1608108SN/A            break;
1618108SN/A          case PrimaryTiming + 1:
1628108SN/A            pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8));
1638108SN/A            break;
1648108SN/A          case SecondaryTiming + 1:
1658108SN/A            pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8));
1668108SN/A            break;
1678108SN/A          case IDEConfig:
1688108SN/A            pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0));
1698108SN/A            break;
1708108SN/A          case IDEConfig + 1:
1718108SN/A            pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8));
1728108SN/A            break;
1738108SN/A          default:
1748108SN/A            panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
1758108SN/A                    offset);
1768108SN/A        }
1778108SN/A        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
1788108SN/A                (uint32_t)pkt->get<uint8_t>());
1798108SN/A        break;
1808108SN/A      case sizeof(uint16_t):
1818108SN/A        switch (offset) {
1828108SN/A          case PrimaryTiming:
1838108SN/A            pkt->set<uint16_t>(primaryTiming);
1848108SN/A            break;
1858108SN/A          case SecondaryTiming:
1868108SN/A            pkt->set<uint16_t>(secondaryTiming);
1878108SN/A            break;
1888108SN/A          case UDMATiming:
1898108SN/A            pkt->set<uint16_t>(udmaTiming);
1908108SN/A            break;
1918108SN/A          case IDEConfig:
1928108SN/A            pkt->set<uint16_t>(ideConfig);
1938108SN/A            break;
1948108SN/A          default:
1958108SN/A            panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
1968108SN/A                    offset);
1978108SN/A        }
1988108SN/A        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
1998108SN/A                (uint32_t)pkt->get<uint16_t>());
2008108SN/A        break;
2018108SN/A      case sizeof(uint32_t):
2028108SN/A        panic("No 32bit reads implemented for this device.");
2038108SN/A        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
2048108SN/A                (uint32_t)pkt->get<uint32_t>());
2055049SN/A        break;
2064780SN/A      default:
2074780SN/A        panic("invalid access size(?) for PCI configspace!\n");
2088108SN/A    }
2098108SN/A    pkt->makeAtomicResponse();
2104780SN/A    return configDelay;
2114780SN/A}
2125049SN/A
2138108SN/A
2144780SN/ATick
2154780SN/AIdeController::writeConfig(PacketPtr pkt)
2164780SN/A{
2178108SN/A    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
2185049SN/A    if (offset < PCI_DEVICE_SPECIFIC) {
2195049SN/A        PciDev::writeConfig(pkt);
2205049SN/A    } else {
2218108SN/A        switch (pkt->getSize()) {
2224780SN/A          case sizeof(uint8_t):
2234780SN/A            switch (offset) {
2244780SN/A              case DeviceTiming:
2254780SN/A                deviceTiming = pkt->get<uint8_t>();
2264780SN/A                break;
2274780SN/A              case UDMAControl:
2288108SN/A                udmaControl = pkt->get<uint8_t>();
2294780SN/A                break;
2304780SN/A              case IDEConfig:
2314780SN/A                replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>());
2328108SN/A                break;
2338108SN/A              case IDEConfig + 1:
2344780SN/A                replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>());
2358108SN/A                break;
2364780SN/A              default:
2374780SN/A                panic("Invalid PCI configuration write "
2388108SN/A                        "for size 1 offset: %#x!\n", offset);
2398108SN/A            }
2404780SN/A            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
2418108SN/A                    offset, (uint32_t)pkt->get<uint8_t>());
2424780SN/A            break;
2434780SN/A          case sizeof(uint16_t):
2448108SN/A            switch (offset) {
2458108SN/A              case PrimaryTiming:
2464780SN/A                primaryTiming = pkt->get<uint16_t>();
2474780SN/A                break;
2484780SN/A              case SecondaryTiming:
2494843SN/A                secondaryTiming = pkt->get<uint16_t>();
2504780SN/A                break;
2517071SN/A              case UDMATiming:
2524780SN/A                udmaTiming = pkt->get<uint16_t>();
2537071SN/A                break;
2544780SN/A              case IDEConfig:
2554780SN/A                ideConfig = pkt->get<uint16_t>();
2564780SN/A                break;
2574780SN/A              default:
2587071SN/A                panic("Invalid PCI configuration write "
2594780SN/A                        "for size 2 offset: %#x!\n",
2604780SN/A                        offset);
2614780SN/A            }
2624780SN/A            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
2634780SN/A                    offset, (uint32_t)pkt->get<uint16_t>());
2644780SN/A            break;
2658108SN/A          case sizeof(uint32_t):
2664780SN/A            panic("Write of unimplemented PCI config. register: %x\n", offset);
2677071SN/A            break;
2684780SN/A          default:
2698108SN/A            panic("invalid access size(?) for PCI configspace!\n");
2708108SN/A        }
2714843SN/A        pkt->makeAtomicResponse();
2724780SN/A    }
2734780SN/A
27411321Ssteve.reinhardt@amd.com    /* Trap command register writes and enable IO/BM as appropriate as well as
2754780SN/A     * BARs. */
2764780SN/A    switch(offset) {
2774780SN/A      case PCI0_BASE_ADDR0:
2784780SN/A        if (BARAddrs[0] != 0)
2798108SN/A            primary.cmdAddr = BARAddrs[0];
2804780SN/A        break;
2817071SN/A
2824780SN/A      case PCI0_BASE_ADDR1:
2834780SN/A        if (BARAddrs[1] != 0)
2844780SN/A            primary.ctrlAddr = BARAddrs[1];
28511321Ssteve.reinhardt@amd.com        break;
2864780SN/A
2878108SN/A      case PCI0_BASE_ADDR2:
2884780SN/A        if (BARAddrs[2] != 0)
2894780SN/A            secondary.cmdAddr = BARAddrs[2];
2904780SN/A        break;
2914780SN/A
2927071SN/A      case PCI0_BASE_ADDR3:
2934791SN/A        if (BARAddrs[3] != 0)
2944780SN/A            secondary.ctrlAddr = BARAddrs[3];
29511321Ssteve.reinhardt@amd.com        break;
2964780SN/A
2974780SN/A      case PCI0_BASE_ADDR4:
2984780SN/A        if (BARAddrs[4] != 0)
2994780SN/A            bmiAddr = BARAddrs[4];
3004780SN/A        break;
3018108SN/A
3024780SN/A      case PCI_COMMAND:
3034780SN/A        ioEnabled = (config.command & htole(PCI_CMD_IOSE));
3048108SN/A        bmEnabled = (config.command & htole(PCI_CMD_BME));
3058108SN/A        break;
3064780SN/A    }
3078108SN/A    return configDelay;
3087071SN/A}
3094780SN/A
3104780SN/Avoid
3114780SN/AIdeController::Channel::accessCommand(Addr offset,
3124780SN/A        int size, uint8_t *data, bool read)
3134780SN/A{
3144780SN/A    const Addr SelectOffset = 6;
3154780SN/A    const uint8_t SelectDevBit = 0x10;
3164780SN/A
3178108SN/A    if (!read && offset == SelectOffset)
3184780SN/A        select(*data & SelectDevBit);
3194780SN/A
3204780SN/A    if (selected == NULL) {
3218108SN/A        assert(size == sizeof(uint8_t));
3228108SN/A        *data = 0;
3234795SN/A    } else if (read) {
3244795SN/A        selected->readCommand(offset, size, data);
3254795SN/A    } else {
3264795SN/A        selected->writeCommand(offset, size, data);
3278108SN/A    }
3284795SN/A}
3298108SN/A
3304795SN/Avoid
3318108SN/AIdeController::Channel::accessControl(Addr offset,
33211321Ssteve.reinhardt@amd.com        int size, uint8_t *data, bool read)
3334795SN/A{
3344795SN/A    if (selected == NULL) {
3354795SN/A        assert(size == sizeof(uint8_t));
3364795SN/A        *data = 0;
3374795SN/A    } else if (read) {
3384795SN/A        selected->readControl(offset, size, data);
3394795SN/A    } else {
3404795SN/A        selected->writeControl(offset, size, data);
3414795SN/A    }
3424795SN/A}
3434795SN/A
3448108SN/Avoid
3454795SN/AIdeController::Channel::accessBMI(Addr offset,
3464795SN/A        int size, uint8_t *data, bool read)
3474795SN/A{
3488108SN/A    assert(offset + size <= sizeof(BMIRegs));
3498108SN/A    if (read) {
3504795SN/A        memcpy(data, (uint8_t *)&bmiRegs + offset, size);
3518108SN/A    } else {
3524795SN/A        switch (offset) {
3534795SN/A          case BMICommand:
3544795SN/A            {
3554795SN/A                if (size != sizeof(uint8_t))
3568108SN/A                    panic("Invalid BMIC write size: %x\n", size);
3578108SN/A
3584795SN/A                BMICommandReg oldVal = bmiRegs.command;
3598108SN/A                BMICommandReg newVal = *data;
3604795SN/A
3618108SN/A                // if a DMA transfer is in progress, R/W control cannot change
3624795SN/A                if (oldVal.startStop && oldVal.rw != newVal.rw)
3634795SN/A                    oldVal.rw = newVal.rw;
3644795SN/A
3654795SN/A                if (oldVal.startStop != newVal.startStop) {
3664795SN/A                    if (selected == NULL)
3674795SN/A                        panic("DMA start for disk which does not exist\n");
3684795SN/A
3694795SN/A                    if (oldVal.startStop) {
3704795SN/A                        DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
3714795SN/A                        bmiRegs.status.active = 0;
3724795SN/A
3738108SN/A                        selected->abortDma();
3748108SN/A                    } else {
3754795SN/A                        DPRINTF(IdeCtrl, "Starting DMA transfer\n");
3764795SN/A                        bmiRegs.status.active = 1;
3778108SN/A
3784795SN/A                        selected->startDma(letoh(bmiRegs.bmidtp));
3794795SN/A                    }
3804795SN/A                }
3814795SN/A
3824795SN/A                bmiRegs.command = newVal;
3834795SN/A            }
3844795SN/A            break;
3854795SN/A          case BMIStatus:
3864795SN/A            {
3874795SN/A                if (size != sizeof(uint8_t))
3884795SN/A                    panic("Invalid BMIS write size: %x\n", size);
3894795SN/A
3904795SN/A                BMIStatusReg oldVal = bmiRegs.status;
3914795SN/A                BMIStatusReg newVal = *data;
3928108SN/A
3934955SN/A                // the BMIDEA bit is read only
3944955SN/A                newVal.active = oldVal.active;
3958108SN/A
3964955SN/A                // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
3974955SN/A                if (oldVal.intStatus && newVal.intStatus)
39811321Ssteve.reinhardt@amd.com                    newVal.intStatus = 0; // clear the interrupt?
3994955SN/A                else
4004795SN/A                    newVal.intStatus = oldVal.intStatus;
4014795SN/A                if (oldVal.dmaError && newVal.dmaError)
4024780SN/A                    newVal.dmaError = 0;
4034780SN/A                else
4048108SN/A                    newVal.dmaError = oldVal.dmaError;
4054780SN/A
406                bmiRegs.status = newVal;
407            }
408            break;
409          case BMIDescTablePtr:
410            if (size != sizeof(uint32_t))
411                panic("Invalid BMIDTP write size: %x\n", size);
412            bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3);
413            break;
414          default:
415            if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
416                    size != sizeof(uint32_t))
417                panic("IDE controller write of invalid write size: %x\n", size);
418            memcpy((uint8_t *)&bmiRegs + offset, data, size);
419        }
420    }
421}
422
423void
424IdeController::dispatchAccess(PacketPtr pkt, bool read)
425{
426    pkt->allocate();
427    if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
428         panic("Bad IDE read size: %d\n", pkt->getSize());
429
430    if (!ioEnabled) {
431        pkt->makeAtomicResponse();
432        DPRINTF(IdeCtrl, "io not enabled\n");
433        return;
434    }
435
436    Addr addr = pkt->getAddr();
437    int size = pkt->getSize();
438    uint8_t *dataPtr = pkt->getPtr<uint8_t>();
439
440    if (addr >= primary.cmdAddr &&
441            addr < (primary.cmdAddr + primary.cmdSize)) {
442        addr -= primary.cmdAddr;
443        primary.accessCommand(addr, size, dataPtr, read);
444    } else if (addr >= primary.ctrlAddr &&
445               addr < (primary.ctrlAddr + primary.ctrlSize)) {
446        addr -= primary.ctrlAddr;
447        primary.accessControl(addr, size, dataPtr, read);
448    } else if (addr >= secondary.cmdAddr &&
449               addr < (secondary.cmdAddr + secondary.cmdSize)) {
450        addr -= secondary.cmdAddr;
451        secondary.accessCommand(addr, size, dataPtr, read);
452    } else if (addr >= secondary.ctrlAddr &&
453               addr < (secondary.ctrlAddr + secondary.ctrlSize)) {
454        addr -= secondary.ctrlAddr;
455        secondary.accessControl(addr, size, dataPtr, read);
456    } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) {
457        if (!read && !bmEnabled)
458            return;
459        addr -= bmiAddr;
460        if (addr < sizeof(Channel::BMIRegs)) {
461            primary.accessBMI(addr, size, dataPtr, read);
462        } else {
463            addr -= sizeof(Channel::BMIRegs);
464            secondary.accessBMI(addr, size, dataPtr, read);
465        }
466    } else {
467        panic("IDE controller access to invalid address: %#x\n", addr);
468    }
469
470    uint32_t data;
471    if (pkt->getSize() == 1)
472        data = pkt->get<uint8_t>();
473    else if (pkt->getSize() == 2)
474        data = pkt->get<uint16_t>();
475    else
476        data = pkt->get<uint32_t>();
477    DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
478            read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
479
480    pkt->makeAtomicResponse();
481}
482
483Tick
484IdeController::read(PacketPtr pkt)
485{
486    dispatchAccess(pkt, true);
487    return pioDelay;
488}
489
490Tick
491IdeController::write(PacketPtr pkt)
492{
493    dispatchAccess(pkt, false);
494    return pioDelay;
495}
496
497void
498IdeController::serialize(std::ostream &os)
499{
500    // Serialize the PciDev base class
501    PciDev::serialize(os);
502
503    // Serialize channels
504    primary.serialize(os);
505    secondary.serialize(os);
506
507    // Serialize config registers
508    SERIALIZE_SCALAR(primaryTiming);
509    SERIALIZE_SCALAR(secondaryTiming);
510    SERIALIZE_SCALAR(deviceTiming);
511    SERIALIZE_SCALAR(udmaControl);
512    SERIALIZE_SCALAR(udmaTiming);
513    SERIALIZE_SCALAR(ideConfig);
514
515    // Serialize internal state
516    SERIALIZE_SCALAR(ioEnabled);
517    SERIALIZE_SCALAR(bmEnabled);
518}
519
520void
521IdeController::Channel::serialize(std::ostream &os)
522{
523    SERIALIZE_SCALAR(cmdAddr);
524    SERIALIZE_SCALAR(cmdSize);
525    SERIALIZE_SCALAR(ctrlAddr);
526    SERIALIZE_SCALAR(ctrlSize);
527    uint8_t command = bmiRegs.command;
528    SERIALIZE_SCALAR(command);
529    SERIALIZE_SCALAR(bmiRegs.reserved0);
530    uint8_t status = bmiRegs.status;
531    SERIALIZE_SCALAR(status);
532    SERIALIZE_SCALAR(bmiRegs.reserved1);
533    SERIALIZE_SCALAR(bmiRegs.bmidtp);
534    SERIALIZE_SCALAR(selectBit);
535}
536
537void
538IdeController::unserialize(Checkpoint *cp, const std::string &section)
539{
540    // Unserialize the PciDev base class
541    PciDev::unserialize(cp, section);
542
543    // Unserialize channels
544    primary.unserialize(cp, section);
545    secondary.unserialize(cp, section);
546
547    // Unserialize config registers
548    UNSERIALIZE_SCALAR(primaryTiming);
549    UNSERIALIZE_SCALAR(secondaryTiming);
550    UNSERIALIZE_SCALAR(deviceTiming);
551    UNSERIALIZE_SCALAR(udmaControl);
552    UNSERIALIZE_SCALAR(udmaTiming);
553    UNSERIALIZE_SCALAR(ideConfig);
554
555    // Unserialize internal state
556    UNSERIALIZE_SCALAR(ioEnabled);
557    UNSERIALIZE_SCALAR(bmEnabled);
558}
559
560void
561IdeController::Channel::unserialize(
562        Checkpoint *cp, const std::string &section)
563{
564    UNSERIALIZE_SCALAR(cmdAddr);
565    UNSERIALIZE_SCALAR(cmdSize);
566    UNSERIALIZE_SCALAR(ctrlAddr);
567    UNSERIALIZE_SCALAR(ctrlSize);
568    uint8_t command;
569    UNSERIALIZE_SCALAR(command);
570    bmiRegs.command = command;
571    UNSERIALIZE_SCALAR(bmiRegs.reserved0);
572    uint8_t status;
573    UNSERIALIZE_SCALAR(status);
574    bmiRegs.status = status;
575    UNSERIALIZE_SCALAR(bmiRegs.reserved1);
576    UNSERIALIZE_SCALAR(bmiRegs.bmidtp);
577    UNSERIALIZE_SCALAR(selectBit);
578    select(selectBit);
579}
580
581IdeController *
582IdeControllerParams::create()
583{
584    return new IdeController(this);
585}
586