ide_disk.hh revision 2565
11760Sstever@eecs.umich.edu/*
22Ssraasch@umich.edu * Copyright (c) 2004-2005 The Regents of The University of Michigan
32Ssraasch@umich.edu * All rights reserved.
42Ssraasch@umich.edu *
52Ssraasch@umich.edu * Redistribution and use in source and binary forms, with or without
62Ssraasch@umich.edu * modification, are permitted provided that the following conditions are
72Ssraasch@umich.edu * met: redistributions of source code must retain the above copyright
82Ssraasch@umich.edu * notice, this list of conditions and the following disclaimer;
92Ssraasch@umich.edu * redistributions in binary form must reproduce the above copyright
102Ssraasch@umich.edu * notice, this list of conditions and the following disclaimer in the
112Ssraasch@umich.edu * documentation and/or other materials provided with the distribution;
122Ssraasch@umich.edu * neither the name of the copyright holders nor the names of its
132Ssraasch@umich.edu * contributors may be used to endorse or promote products derived from
142Ssraasch@umich.edu * this software without specific prior written permission.
152Ssraasch@umich.edu *
162Ssraasch@umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
172Ssraasch@umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
182Ssraasch@umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
192Ssraasch@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
202Ssraasch@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
212Ssraasch@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
222Ssraasch@umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
232Ssraasch@umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
242Ssraasch@umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
252Ssraasch@umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
262Ssraasch@umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
272Ssraasch@umich.edu */
282Ssraasch@umich.edu
292Ssraasch@umich.edu/** @file
302Ssraasch@umich.edu * Device model for an IDE disk
312Ssraasch@umich.edu */
322Ssraasch@umich.edu
332Ssraasch@umich.edu#ifndef __IDE_DISK_HH__
34202Sbinkertn@umich.edu#define __IDE_DISK_HH__
352Ssraasch@umich.edu
36202Sbinkertn@umich.edu#include "dev/disk_image.hh"
37202Sbinkertn@umich.edu#include "dev/ide_atareg.h"
382Ssraasch@umich.edu#include "dev/ide_ctrl.hh"
39202Sbinkertn@umich.edu#include "dev/ide_wdcreg.h"
402Ssraasch@umich.edu#include "dev/io_device.hh"
412Ssraasch@umich.edu#include "sim/eventq.hh"
422Ssraasch@umich.edu
432Ssraasch@umich.edu#define DMA_BACKOFF_PERIOD 200
442Ssraasch@umich.edu
452Ssraasch@umich.edu#define MAX_DMA_SIZE    (131072)  // 128K
462Ssraasch@umich.edu#define MAX_MULTSECT    (128)
47202Sbinkertn@umich.edu
48202Sbinkertn@umich.edu#define PRD_BASE_MASK  0xfffffffe
492Ssraasch@umich.edu#define PRD_COUNT_MASK 0xfffe
502Ssraasch@umich.edu#define PRD_EOT_MASK   0x8000
512Ssraasch@umich.edu
522Ssraasch@umich.edutypedef struct PrdEntry {
532Ssraasch@umich.edu    uint32_t baseAddr;
542Ssraasch@umich.edu    uint16_t byteCount;
552Ssraasch@umich.edu    uint16_t endOfTable;
562Ssraasch@umich.edu} PrdEntry_t;
572Ssraasch@umich.edu
582Ssraasch@umich.educlass PrdTableEntry {
592Ssraasch@umich.edu  public:
602Ssraasch@umich.edu    PrdEntry_t entry;
612Ssraasch@umich.edu
622Ssraasch@umich.edu    uint32_t getBaseAddr()
632Ssraasch@umich.edu    {
642Ssraasch@umich.edu        return (entry.baseAddr & PRD_BASE_MASK);
652Ssraasch@umich.edu    }
66
67    uint32_t getByteCount()
68    {
69        return ((entry.byteCount == 0) ? MAX_DMA_SIZE :
70                (entry.byteCount & PRD_COUNT_MASK));
71    }
72
73    uint16_t getEOT()
74    {
75        return (entry.endOfTable & PRD_EOT_MASK);
76    }
77};
78
79#define DATA_OFFSET     (0)
80#define ERROR_OFFSET    (1)
81#define FEATURES_OFFSET (1)
82#define NSECTOR_OFFSET  (2)
83#define SECTOR_OFFSET   (3)
84#define LCYL_OFFSET     (4)
85#define HCYL_OFFSET     (5)
86#define SELECT_OFFSET   (6)
87#define DRIVE_OFFSET    (6)
88#define STATUS_OFFSET   (7)
89#define COMMAND_OFFSET  (7)
90
91#define CONTROL_OFFSET  (2)
92#define ALTSTAT_OFFSET  (2)
93
94#define SELECT_DEV_BIT  0x10
95#define CONTROL_RST_BIT 0x04
96#define CONTROL_IEN_BIT 0x02
97#define STATUS_BSY_BIT  0x80
98#define STATUS_DRDY_BIT 0x40
99#define STATUS_DRQ_BIT  0x08
100#define STATUS_SEEK_BIT 0x10
101#define STATUS_DF_BIT   0x20
102#define DRIVE_LBA_BIT   0x40
103
104#define DEV0 (0)
105#define DEV1 (1)
106
107typedef struct CommandReg {
108    uint16_t data;
109    uint8_t error;
110    uint8_t sec_count;
111    uint8_t sec_num;
112    uint8_t cyl_low;
113    uint8_t cyl_high;
114    union {
115        uint8_t drive;
116        uint8_t head;
117    };
118    uint8_t command;
119} CommandReg_t;
120
121typedef enum Events {
122    None = 0,
123    Transfer,
124    ReadWait,
125    WriteWait,
126    PrdRead,
127    DmaRead,
128    DmaWrite
129} Events_t;
130
131typedef enum DevAction {
132    ACT_NONE = 0,
133    ACT_CMD_WRITE,
134    ACT_CMD_COMPLETE,
135    ACT_CMD_ERROR,
136    ACT_SELECT_WRITE,
137    ACT_STAT_READ,
138    ACT_DATA_READY,
139    ACT_DATA_READ_BYTE,
140    ACT_DATA_READ_SHORT,
141    ACT_DATA_WRITE_BYTE,
142    ACT_DATA_WRITE_SHORT,
143    ACT_DMA_READY,
144    ACT_DMA_DONE,
145    ACT_SRST_SET,
146    ACT_SRST_CLEAR
147} DevAction_t;
148
149typedef enum DevState {
150    // Device idle
151    Device_Idle_S = 0,
152    Device_Idle_SI,
153    Device_Idle_NS,
154
155    // Software reset
156    Device_Srst,
157
158    // Non-data commands
159    Command_Execution,
160
161    // PIO data-in (data to host)
162    Prepare_Data_In,
163    Data_Ready_INTRQ_In,
164    Transfer_Data_In,
165
166    // PIO data-out (data from host)
167    Prepare_Data_Out,
168    Data_Ready_INTRQ_Out,
169    Transfer_Data_Out,
170
171    // DMA protocol
172    Prepare_Data_Dma,
173    Transfer_Data_Dma
174} DevState_t;
175
176typedef enum DmaState {
177    Dma_Idle = 0,
178    Dma_Start,
179    Dma_Transfer
180} DmaState_t;
181
182class PhysicalMemory;
183class IdeController;
184
185/**
186 * IDE Disk device model
187 */
188class IdeDisk : public SimObject
189{
190  protected:
191    /** The IDE controller for this disk. */
192    IdeController *ctrl;
193    /** The image that contains the data of this disk. */
194    DiskImage *image;
195
196  protected:
197    /** The disk delay in microseconds. */
198    int diskDelay;
199
200  private:
201    /** Drive identification structure for this disk */
202    struct ataparams driveID;
203    /** Data buffer for transfers */
204    uint8_t *dataBuffer;
205    /** Number of bytes in command data transfer */
206    uint32_t cmdBytes;
207    /** Number of bytes left in command data transfer */
208    uint32_t cmdBytesLeft;
209    /** Number of bytes left in DRQ block */
210    uint32_t drqBytesLeft;
211    /** Current sector in access */
212    uint32_t curSector;
213    /** Command block registers */
214    CommandReg_t cmdReg;
215    /** Status register */
216    uint8_t status;
217    /** Interrupt enable bit */
218    bool nIENBit;
219    /** Device state */
220    DevState_t devState;
221    /** Dma state */
222    DmaState_t dmaState;
223    /** Dma transaction is a read */
224    bool dmaRead;
225    /** PRD table base address */
226    uint32_t curPrdAddr;
227    /** PRD entry */
228    PrdTableEntry curPrd;
229    /** Device ID (master=0/slave=1) */
230    int devID;
231    /** Interrupt pending */
232    bool intrPending;
233
234  public:
235    /**
236     * Create and initialize this Disk.
237     * @param name The name of this disk.
238     * @param img The disk image of this disk.
239     * @param id The disk ID (master=0/slave=1)
240     * @param disk_delay The disk delay in milliseconds
241     */
242    IdeDisk(const std::string &name, DiskImage *img, int id, Tick disk_delay);
243
244    /**
245     * Delete the data buffer.
246     */
247    ~IdeDisk();
248
249    /**
250     * Reset the device state
251     */
252    void reset(int id);
253
254    /**
255     * Set the controller for this device
256     * @param c The IDE controller
257     */
258    void setController(IdeController *c) {
259        if (ctrl) panic("Cannot change the controller once set!\n");
260        ctrl = c;
261    }
262
263    // Device register read/write
264    void read(const Addr &offset, IdeRegType regtype, uint8_t *data);
265    void write(const Addr &offset, IdeRegType regtype, const uint8_t *data);
266
267    // Start/abort functions
268    void startDma(const uint32_t &prdTableBase);
269    void abortDma();
270
271  private:
272    void startCommand();
273
274    // Interrupt management
275    void intrPost();
276    void intrClear();
277
278    // DMA stuff
279    void doDmaTransfer();
280    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>;
281    EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent;
282
283    void doDmaDataRead();
284
285    void doDmaRead();
286    ChunkGenerator *dmaReadCG;
287    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>;
288    EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent;
289
290    void doDmaDataWrite();
291
292    void doDmaWrite();
293    ChunkGenerator *dmaWriteCG;
294    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>;
295    EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent;
296
297    void dmaPrdReadDone();
298    friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>;
299    EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent;
300
301    void dmaReadDone();
302    friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>;
303    EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent;
304
305    void dmaWriteDone();
306    friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>;
307    EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent;
308
309    // Disk image read/write
310    void readDisk(uint32_t sector, uint8_t *data);
311    void writeDisk(uint32_t sector, uint8_t *data);
312
313    // State machine management
314    void updateState(DevAction_t action);
315
316    // Utility functions
317    bool isBSYSet() { return (status & STATUS_BSY_BIT); }
318    bool isIENSet() { return nIENBit; }
319    bool isDEVSelect();
320
321    void setComplete()
322    {
323        // clear out the status byte
324        status = 0;
325        // set the DRDY bit
326        status |= STATUS_DRDY_BIT;
327        // set the SEEK bit
328        status |= STATUS_SEEK_BIT;
329    }
330
331    uint32_t getLBABase()
332    {
333        return  (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) |
334                       (cmdReg.cyl_low << 8) | (cmdReg.sec_num));
335    }
336
337    inline Addr pciToDma(Addr pciAddr);
338
339    /**
340     * Serialize this object to the given output stream.
341     * @param os The stream to serialize to.
342     */
343    void serialize(std::ostream &os);
344
345    /**
346     * Reconstruct the state of this object from a checkpoint.
347     * @param cp The checkpoint to use.
348     * @param section The section name describing this object.
349     */
350    void unserialize(Checkpoint *cp, const std::string &section);
351};
352
353
354#endif // __IDE_DISK_HH__
355