ide_disk.hh revision 5999
12SN/A/*
29955SGeoffrey.Blake@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan
39955SGeoffrey.Blake@arm.com * All rights reserved.
49955SGeoffrey.Blake@arm.com *
59955SGeoffrey.Blake@arm.com * Redistribution and use in source and binary forms, with or without
69955SGeoffrey.Blake@arm.com * modification, are permitted provided that the following conditions are
79955SGeoffrey.Blake@arm.com * met: redistributions of source code must retain the above copyright
89955SGeoffrey.Blake@arm.com * notice, this list of conditions and the following disclaimer;
99955SGeoffrey.Blake@arm.com * redistributions in binary form must reproduce the above copyright
109955SGeoffrey.Blake@arm.com * notice, this list of conditions and the following disclaimer in the
119955SGeoffrey.Blake@arm.com * documentation and/or other materials provided with the distribution;
129955SGeoffrey.Blake@arm.com * neither the name of the copyright holders nor the names of its
139955SGeoffrey.Blake@arm.com * contributors may be used to endorse or promote products derived from
141762SN/A * this software without specific prior written permission.
157778Sgblack@eecs.umich.edu *
162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272SN/A *
282SN/A * Authors: Andrew Schultz
292SN/A */
302SN/A
312SN/A/** @file
322SN/A * Device model for an IDE disk
332SN/A */
342SN/A
352SN/A#ifndef __IDE_DISK_HH__
362SN/A#define __IDE_DISK_HH__
372SN/A
382SN/A#include "base/statistics.hh"
392SN/A#include "dev/disk_image.hh"
402665Ssaidi@eecs.umich.edu#include "dev/ide_atareg.h"
412665Ssaidi@eecs.umich.edu#include "dev/ide_ctrl.hh"
427778Sgblack@eecs.umich.edu#include "dev/ide_wdcreg.h"
439955SGeoffrey.Blake@arm.com#include "dev/io_device.hh"
442SN/A#include "sim/eventq.hh"
452SN/A#include "params/IdeDisk.hh"
468607Sgblack@eecs.umich.edu
476712Snate@binkert.org
482SN/Aclass ChunkGenerator;
492SN/A
502SN/A#define DMA_BACKOFF_PERIOD 200
5156SN/A
526216Snate@binkert.org#define MAX_DMA_SIZE    (131072)  // 128K
536214Snate@binkert.org#define MAX_MULTSECT    (128)
542SN/A
551078SN/A#define PRD_BASE_MASK  0xfffffffe
561114SN/A#define PRD_COUNT_MASK 0xfffe
571114SN/A#define PRD_EOT_MASK   0x8000
581114SN/A
591114SN/Atypedef struct PrdEntry {
601114SN/A    uint32_t baseAddr;
611114SN/A    uint16_t byteCount;
621114SN/A    uint16_t endOfTable;
631114SN/A} PrdEntry_t;
641114SN/A
6510251Satgutier@umich.educlass PrdTableEntry {
6610251Satgutier@umich.edu  public:
671114SN/A    PrdEntry_t entry;
681114SN/A
691114SN/A    uint32_t getBaseAddr()
701114SN/A    {
7110251Satgutier@umich.edu        return (entry.baseAddr & PRD_BASE_MASK);
7210251Satgutier@umich.edu    }
731114SN/A
741114SN/A    uint32_t getByteCount()
751114SN/A    {
761114SN/A        return ((entry.byteCount == 0) ? MAX_DMA_SIZE :
771114SN/A                (entry.byteCount & PRD_COUNT_MASK));
781114SN/A    }
791114SN/A
801114SN/A    uint16_t getEOT()
811114SN/A    {
821114SN/A        return (entry.endOfTable & PRD_EOT_MASK);
831114SN/A    }
841114SN/A};
851114SN/A
861114SN/A#define DATA_OFFSET     (0)
871114SN/A#define ERROR_OFFSET    (1)
881114SN/A#define FEATURES_OFFSET (1)
891114SN/A#define NSECTOR_OFFSET  (2)
901114SN/A#define SECTOR_OFFSET   (3)
911114SN/A#define LCYL_OFFSET     (4)
921114SN/A#define HCYL_OFFSET     (5)
931114SN/A#define SELECT_OFFSET   (6)
941114SN/A#define DRIVE_OFFSET    (6)
951114SN/A#define STATUS_OFFSET   (7)
961114SN/A#define COMMAND_OFFSET  (7)
971114SN/A
981114SN/A#define CONTROL_OFFSET  (2)
991114SN/A#define ALTSTAT_OFFSET  (2)
1001114SN/A
1011114SN/A#define SELECT_DEV_BIT  0x10
1021114SN/A#define CONTROL_RST_BIT 0x04
1031114SN/A#define CONTROL_IEN_BIT 0x02
1041114SN/A#define STATUS_BSY_BIT  0x80
1051114SN/A#define STATUS_DRDY_BIT 0x40
1061114SN/A#define STATUS_DRQ_BIT  0x08
1071114SN/A#define STATUS_SEEK_BIT 0x10
1081114SN/A#define STATUS_DF_BIT   0x20
1091114SN/A#define DRIVE_LBA_BIT   0x40
1101114SN/A
1111114SN/A#define DEV0 (0)
1121114SN/A#define DEV1 (1)
1131114SN/A
1141114SN/Atypedef struct CommandReg {
1151114SN/A    uint16_t data;
1162SN/A    uint8_t error;
1171114SN/A    uint8_t sec_count;
1182SN/A    uint8_t sec_num;
1192SN/A    uint8_t cyl_low;
1201114SN/A    uint8_t cyl_high;
1212SN/A    union {
1222SN/A        uint8_t drive;
1232SN/A        uint8_t head;
1241114SN/A    };
1251114SN/A    uint8_t command;
1262SN/A} CommandReg_t;
12710252Satgutier@umich.edu
1281114SN/Atypedef enum Events {
1291114SN/A    None = 0,
1301114SN/A    Transfer,
1311114SN/A    ReadWait,
1321114SN/A    WriteWait,
1331114SN/A    PrdRead,
1341114SN/A    DmaRead,
1351114SN/A    DmaWrite
1362SN/A} Events_t;
1372SN/A
1387777Sgblack@eecs.umich.edutypedef enum DevAction {
1397777Sgblack@eecs.umich.edu    ACT_NONE = 0,
1407777Sgblack@eecs.umich.edu    ACT_CMD_WRITE,
1417777Sgblack@eecs.umich.edu    ACT_CMD_COMPLETE,
1427777Sgblack@eecs.umich.edu    ACT_CMD_ERROR,
1437777Sgblack@eecs.umich.edu    ACT_SELECT_WRITE,
1447777Sgblack@eecs.umich.edu    ACT_STAT_READ,
1457777Sgblack@eecs.umich.edu    ACT_DATA_READY,
1467777Sgblack@eecs.umich.edu    ACT_DATA_READ_BYTE,
1477777Sgblack@eecs.umich.edu    ACT_DATA_READ_SHORT,
1487777Sgblack@eecs.umich.edu    ACT_DATA_WRITE_BYTE,
1497777Sgblack@eecs.umich.edu    ACT_DATA_WRITE_SHORT,
1507777Sgblack@eecs.umich.edu    ACT_DMA_READY,
1517777Sgblack@eecs.umich.edu    ACT_DMA_DONE,
1527777Sgblack@eecs.umich.edu    ACT_SRST_SET,
1537777Sgblack@eecs.umich.edu    ACT_SRST_CLEAR
1547777Sgblack@eecs.umich.edu} DevAction_t;
1557777Sgblack@eecs.umich.edu
1567777Sgblack@eecs.umich.edutypedef enum DevState {
1577814Sgblack@eecs.umich.edu    // Device idle
1587814Sgblack@eecs.umich.edu    Device_Idle_S = 0,
1597777Sgblack@eecs.umich.edu    Device_Idle_SI,
1607777Sgblack@eecs.umich.edu    Device_Idle_NS,
1617777Sgblack@eecs.umich.edu
1627777Sgblack@eecs.umich.edu    // Software reset
1637777Sgblack@eecs.umich.edu    Device_Srst,
1647777Sgblack@eecs.umich.edu
1657777Sgblack@eecs.umich.edu    // Non-data commands
1667777Sgblack@eecs.umich.edu    Command_Execution,
1677777Sgblack@eecs.umich.edu
1687777Sgblack@eecs.umich.edu    // PIO data-in (data to host)
1697777Sgblack@eecs.umich.edu    Prepare_Data_In,
1707777Sgblack@eecs.umich.edu    Data_Ready_INTRQ_In,
1717777Sgblack@eecs.umich.edu    Transfer_Data_In,
1727777Sgblack@eecs.umich.edu
1737777Sgblack@eecs.umich.edu    // PIO data-out (data from host)
1747777Sgblack@eecs.umich.edu    Prepare_Data_Out,
1757777Sgblack@eecs.umich.edu    Data_Ready_INTRQ_Out,
1767777Sgblack@eecs.umich.edu    Transfer_Data_Out,
1777777Sgblack@eecs.umich.edu
1787777Sgblack@eecs.umich.edu    // DMA protocol
1797777Sgblack@eecs.umich.edu    Prepare_Data_Dma,
1807777Sgblack@eecs.umich.edu    Transfer_Data_Dma
1817777Sgblack@eecs.umich.edu} DevState_t;
1827777Sgblack@eecs.umich.edu
1837777Sgblack@eecs.umich.edutypedef enum DmaState {
1847777Sgblack@eecs.umich.edu    Dma_Idle = 0,
1857777Sgblack@eecs.umich.edu    Dma_Start,
1867777Sgblack@eecs.umich.edu    Dma_Transfer
1877777Sgblack@eecs.umich.edu} DmaState_t;
1887777Sgblack@eecs.umich.edu
1897777Sgblack@eecs.umich.educlass PhysicalMemory;
1907777Sgblack@eecs.umich.educlass IdeController;
1917777Sgblack@eecs.umich.edu
1927777Sgblack@eecs.umich.edu/**
1937777Sgblack@eecs.umich.edu * IDE Disk device model
1947777Sgblack@eecs.umich.edu */
1957777Sgblack@eecs.umich.educlass IdeDisk : public SimObject
1967777Sgblack@eecs.umich.edu{
1977777Sgblack@eecs.umich.edu  protected:
1987777Sgblack@eecs.umich.edu    /** The IDE controller for this disk. */
1997777Sgblack@eecs.umich.edu    IdeController *ctrl;
2007777Sgblack@eecs.umich.edu    /** The image that contains the data of this disk. */
2017777Sgblack@eecs.umich.edu    DiskImage *image;
2027777Sgblack@eecs.umich.edu
2037777Sgblack@eecs.umich.edu  protected:
2047777Sgblack@eecs.umich.edu    /** The disk delay in microseconds. */
2051078SN/A    int diskDelay;
2061114SN/A
2071078SN/A  private:
2081114SN/A    /** Drive identification structure for this disk */
2091114SN/A    struct ataparams driveID;
2101078SN/A    /** Data buffer for transfers */
2111114SN/A    uint8_t *dataBuffer;
2121114SN/A    /** Number of bytes in command data transfer */
2131114SN/A    uint32_t cmdBytes;
2141114SN/A    /** Number of bytes left in command data transfer */
2151114SN/A    uint32_t cmdBytesLeft;
2161114SN/A    /** Number of bytes left in DRQ block */
2171114SN/A    uint32_t drqBytesLeft;
2181114SN/A    /** Current sector in access */
2191114SN/A    uint32_t curSector;
2201114SN/A    /** Command block registers */
2211114SN/A    CommandReg_t cmdReg;
2221114SN/A    /** Status register */
2239955SGeoffrey.Blake@arm.com    uint8_t status;
2249955SGeoffrey.Blake@arm.com    /** Interrupt enable bit */
2259955SGeoffrey.Blake@arm.com    bool nIENBit;
2269955SGeoffrey.Blake@arm.com    /** Device state */
2279955SGeoffrey.Blake@arm.com    DevState_t devState;
2289955SGeoffrey.Blake@arm.com    /** Dma state */
2299955SGeoffrey.Blake@arm.com    DmaState_t dmaState;
2309955SGeoffrey.Blake@arm.com    /** Dma transaction is a read */
2319955SGeoffrey.Blake@arm.com    bool dmaRead;
2329955SGeoffrey.Blake@arm.com    /** PRD table base address */
2331114SN/A    uint32_t curPrdAddr;
2349955SGeoffrey.Blake@arm.com    /** PRD entry */
2359955SGeoffrey.Blake@arm.com    PrdTableEntry curPrd;
2369955SGeoffrey.Blake@arm.com    /** Device ID (master=0/slave=1) */
2379955SGeoffrey.Blake@arm.com    int devID;
2389955SGeoffrey.Blake@arm.com    /** Interrupt pending */
2399955SGeoffrey.Blake@arm.com    bool intrPending;
2409955SGeoffrey.Blake@arm.com
2419955SGeoffrey.Blake@arm.com    Stats::Scalar dmaReadFullPages;
2429955SGeoffrey.Blake@arm.com    Stats::Scalar dmaReadBytes;
2439955SGeoffrey.Blake@arm.com    Stats::Scalar dmaReadTxs;
2449955SGeoffrey.Blake@arm.com    Stats::Scalar dmaWriteFullPages;
2451114SN/A    Stats::Scalar dmaWriteBytes;
2461114SN/A    Stats::Scalar dmaWriteTxs;
2471114SN/A    Stats::Formula rdBandwidth;
2489955SGeoffrey.Blake@arm.com    Stats::Formula wrBandwidth;
2499955SGeoffrey.Blake@arm.com    Stats::Formula totBandwidth;
2509955SGeoffrey.Blake@arm.com    Stats::Formula totBytes;
2519955SGeoffrey.Blake@arm.com
2529955SGeoffrey.Blake@arm.com  public:
2539955SGeoffrey.Blake@arm.com    typedef IdeDiskParams Params;
2549955SGeoffrey.Blake@arm.com    IdeDisk(const Params *p);
2559955SGeoffrey.Blake@arm.com
2569955SGeoffrey.Blake@arm.com    /**
2579955SGeoffrey.Blake@arm.com     * Delete the data buffer.
2581114SN/A     */
2591114SN/A    ~IdeDisk();
2601114SN/A
2611114SN/A    /**
2621114SN/A     * Reset the device state
2631114SN/A     */
2641114SN/A    void reset(int id);
2651114SN/A
2661114SN/A    /**
2671114SN/A     * Register Statistics
2681114SN/A     */
2691114SN/A    void regStats();
2701114SN/A
2711114SN/A    /**
2721114SN/A     * Set the controller for this device
2731114SN/A     * @param c The IDE controller
2741114SN/A     */
2751114SN/A    void setController(IdeController *c) {
2761114SN/A        if (ctrl) panic("Cannot change the controller once set!\n");
2771114SN/A        ctrl = c;
2781114SN/A    }
2791114SN/A
2809955SGeoffrey.Blake@arm.com    // Device register read/write
2819955SGeoffrey.Blake@arm.com    void readCommand(const Addr offset, int size, uint8_t *data);
2829955SGeoffrey.Blake@arm.com    void readControl(const Addr offset, int size, uint8_t *data);
2839955SGeoffrey.Blake@arm.com    void writeCommand(const Addr offset, int size, const uint8_t *data);
2849955SGeoffrey.Blake@arm.com    void writeControl(const Addr offset, int size, const uint8_t *data);
2859955SGeoffrey.Blake@arm.com
2869955SGeoffrey.Blake@arm.com    // Start/abort functions
2879955SGeoffrey.Blake@arm.com    void startDma(const uint32_t &prdTableBase);
2889955SGeoffrey.Blake@arm.com    void abortDma();
2899955SGeoffrey.Blake@arm.com
2909955SGeoffrey.Blake@arm.com  private:
2919955SGeoffrey.Blake@arm.com    void startCommand();
2929955SGeoffrey.Blake@arm.com
2939955SGeoffrey.Blake@arm.com    // Interrupt management
2949955SGeoffrey.Blake@arm.com    void intrPost();
2959955SGeoffrey.Blake@arm.com    void intrClear();
2969955SGeoffrey.Blake@arm.com
2979955SGeoffrey.Blake@arm.com    // DMA stuff
2989955SGeoffrey.Blake@arm.com    void doDmaTransfer();
2999955SGeoffrey.Blake@arm.com    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>;
3009955SGeoffrey.Blake@arm.com    EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent;
3019955SGeoffrey.Blake@arm.com
3029955SGeoffrey.Blake@arm.com    void doDmaDataRead();
3039955SGeoffrey.Blake@arm.com
3049955SGeoffrey.Blake@arm.com    void doDmaRead();
3059955SGeoffrey.Blake@arm.com    ChunkGenerator *dmaReadCG;
3069955SGeoffrey.Blake@arm.com    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>;
3079955SGeoffrey.Blake@arm.com    EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent;
3089955SGeoffrey.Blake@arm.com
3099955SGeoffrey.Blake@arm.com    void doDmaDataWrite();
3109955SGeoffrey.Blake@arm.com
3119955SGeoffrey.Blake@arm.com    void doDmaWrite();
3129955SGeoffrey.Blake@arm.com    ChunkGenerator *dmaWriteCG;
3139955SGeoffrey.Blake@arm.com    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>;
3149955SGeoffrey.Blake@arm.com    EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent;
3159955SGeoffrey.Blake@arm.com
3169955SGeoffrey.Blake@arm.com    void dmaPrdReadDone();
3179955SGeoffrey.Blake@arm.com    friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>;
3189955SGeoffrey.Blake@arm.com    EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent;
3199955SGeoffrey.Blake@arm.com
3209955SGeoffrey.Blake@arm.com    void dmaReadDone();
3219955SGeoffrey.Blake@arm.com    friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>;
3229955SGeoffrey.Blake@arm.com    EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent;
3239955SGeoffrey.Blake@arm.com
3249955SGeoffrey.Blake@arm.com    void dmaWriteDone();
3259955SGeoffrey.Blake@arm.com    friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>;
3269955SGeoffrey.Blake@arm.com    EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent;
3279955SGeoffrey.Blake@arm.com
3289955SGeoffrey.Blake@arm.com    // Disk image read/write
3299955SGeoffrey.Blake@arm.com    void readDisk(uint32_t sector, uint8_t *data);
3309955SGeoffrey.Blake@arm.com    void writeDisk(uint32_t sector, uint8_t *data);
3319955SGeoffrey.Blake@arm.com
3329955SGeoffrey.Blake@arm.com    // State machine management
3339955SGeoffrey.Blake@arm.com    void updateState(DevAction_t action);
3349955SGeoffrey.Blake@arm.com
3359955SGeoffrey.Blake@arm.com    // Utility functions
3369955SGeoffrey.Blake@arm.com    bool isBSYSet() { return (status & STATUS_BSY_BIT); }
3379955SGeoffrey.Blake@arm.com    bool isIENSet() { return nIENBit; }
3389955SGeoffrey.Blake@arm.com    bool isDEVSelect();
3399955SGeoffrey.Blake@arm.com
3409955SGeoffrey.Blake@arm.com    void setComplete()
3419955SGeoffrey.Blake@arm.com    {
3429955SGeoffrey.Blake@arm.com        // clear out the status byte
3439955SGeoffrey.Blake@arm.com        status = 0;
3449955SGeoffrey.Blake@arm.com        // set the DRDY bit
3459955SGeoffrey.Blake@arm.com        status |= STATUS_DRDY_BIT;
3469955SGeoffrey.Blake@arm.com        // set the SEEK bit
3479955SGeoffrey.Blake@arm.com        status |= STATUS_SEEK_BIT;
3489955SGeoffrey.Blake@arm.com    }
3499955SGeoffrey.Blake@arm.com
3509955SGeoffrey.Blake@arm.com    uint32_t getLBABase()
3519955SGeoffrey.Blake@arm.com    {
3529955SGeoffrey.Blake@arm.com        return  (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) |
3539955SGeoffrey.Blake@arm.com                       (cmdReg.cyl_low << 8) | (cmdReg.sec_num));
3549955SGeoffrey.Blake@arm.com    }
3559955SGeoffrey.Blake@arm.com
3561114SN/A    inline Addr pciToDma(Addr pciAddr);
3571114SN/A
3581114SN/A    /**
3591114SN/A     * Serialize this object to the given output stream.
3601114SN/A     * @param os The stream to serialize to.
3611114SN/A     */
3621114SN/A    void serialize(std::ostream &os);
3631114SN/A
3641114SN/A    /**
3651114SN/A     * Reconstruct the state of this object from a checkpoint.
3661114SN/A     * @param cp The checkpoint to use.
3671114SN/A     * @param section The section name describing this object.
3681114SN/A     */
3691114SN/A    void unserialize(Checkpoint *cp, const std::string &section);
3701114SN/A};
3711114SN/A
3721114SN/A
3731114SN/A#endif // __IDE_DISK_HH__
3741114SN/A