ide_disk.hh revision 1817
1/*
2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @file
30 * Device model for an IDE disk
31 */
32
33#ifndef __IDE_DISK_HH__
34#define __IDE_DISK_HH__
35
36#include "dev/disk_image.hh"
37#include "dev/ide_atareg.h"
38#include "dev/ide_ctrl.hh"
39#include "dev/ide_wdcreg.h"
40#include "dev/io_device.hh"
41#include "sim/eventq.hh"
42
43#define DMA_BACKOFF_PERIOD 200
44
45#define MAX_DMA_SIZE    (65536)  // 64K
46#define MAX_MULTSECT    (128)
47
48#define PRD_BASE_MASK  0xfffffffe
49#define PRD_COUNT_MASK 0xfffe
50#define PRD_EOT_MASK   0x8000
51
52typedef struct PrdEntry {
53    uint32_t baseAddr;
54    uint16_t byteCount;
55    uint16_t endOfTable;
56} PrdEntry_t;
57
58class PrdTableEntry {
59  public:
60    PrdEntry_t entry;
61
62    uint32_t getBaseAddr()
63    {
64        return (entry.baseAddr & PRD_BASE_MASK);
65    }
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 DMA interface to use for transfers */
194    DMAInterface<Bus> *dmaInterface;
195    /** The image that contains the data of this disk. */
196    DiskImage *image;
197    /** Pointer to physical memory for DMA transfers */
198    PhysicalMemory *physmem;
199
200  protected:
201    /** The disk delay in microseconds. */
202    int diskDelay;
203
204  private:
205    /** Drive identification structure for this disk */
206    struct ataparams driveID;
207    /** Data buffer for transfers */
208    uint8_t *dataBuffer;
209    /** Number of bytes in command data transfer */
210    uint32_t cmdBytes;
211    /** Number of bytes left in command data transfer */
212    uint32_t cmdBytesLeft;
213    /** Number of bytes left in DRQ block */
214    uint32_t drqBytesLeft;
215    /** Current sector in access */
216    uint32_t curSector;
217    /** Command block registers */
218    CommandReg_t cmdReg;
219    /** Status register */
220    uint8_t status;
221    /** Interrupt enable bit */
222    bool nIENBit;
223    /** Device state */
224    DevState_t devState;
225    /** Dma state */
226    DmaState_t dmaState;
227    /** Dma transaction is a read */
228    bool dmaRead;
229    /** PRD table base address */
230    uint32_t curPrdAddr;
231    /** PRD entry */
232    PrdTableEntry curPrd;
233    /** Number of bytes transfered by DMA interface for current transfer */
234    uint32_t dmaInterfaceBytes;
235    /** Device ID (master=0/slave=1) */
236    int devID;
237    /** Interrupt pending */
238    bool intrPending;
239
240  public:
241    /**
242     * Create and initialize this Disk.
243     * @param name The name of this disk.
244     * @param img The disk image of this disk.
245     * @param phys Pointer to physical memory
246     * @param id The disk ID (master=0/slave=1)
247     * @param disk_delay The disk delay in milliseconds
248     */
249    IdeDisk(const std::string &name, DiskImage *img, PhysicalMemory *phys,
250            int id, Tick disk_delay);
251
252    /**
253     * Delete the data buffer.
254     */
255    ~IdeDisk();
256
257    /**
258     * Reset the device state
259     */
260    void reset(int id);
261
262    /**
263     * Set the controller for this device
264     * @param c The IDE controller
265     */
266    void setController(IdeController *c, DMAInterface<Bus> *dmaIntr) {
267        if (ctrl) panic("Cannot change the controller once set!\n");
268        ctrl = c;
269        dmaInterface = dmaIntr;
270    }
271
272    // Device register read/write
273    void read(const Addr &offset, IdeRegType regtype, uint8_t *data);
274    void write(const Addr &offset, IdeRegType regtype, const uint8_t *data);
275
276    // Start/abort functions
277    void startDma(const uint32_t &prdTableBase);
278    void abortDma();
279
280  private:
281    void startCommand();
282
283    // Interrupt management
284    void intrPost();
285    void intrClear();
286
287    // DMA stuff
288    void doDmaTransfer();
289    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>;
290    EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent;
291
292    void doDmaRead();
293    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>;
294    EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent;
295
296    void doDmaWrite();
297    friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>;
298    EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent;
299
300    void dmaPrdReadDone();
301    friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>;
302    EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent;
303
304    void dmaReadDone();
305    friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>;
306    EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent;
307
308    void dmaWriteDone();
309    friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>;
310    EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent;
311
312    // Disk image read/write
313    void readDisk(uint32_t sector, uint8_t *data);
314    void writeDisk(uint32_t sector, uint8_t *data);
315
316    // State machine management
317    void updateState(DevAction_t action);
318
319    // Utility functions
320    bool isBSYSet() { return (status & STATUS_BSY_BIT); }
321    bool isIENSet() { return nIENBit; }
322    bool isDEVSelect();
323
324    void setComplete()
325    {
326        // clear out the status byte
327        status = 0;
328        // set the DRDY bit
329        status |= STATUS_DRDY_BIT;
330        // set the SEEK bit
331        status |= STATUS_SEEK_BIT;
332    }
333
334    uint32_t getLBABase()
335    {
336        return  (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) |
337                       (cmdReg.cyl_low << 8) | (cmdReg.sec_num));
338    }
339
340    inline Addr pciToDma(Addr pciAddr);
341
342    uint32_t bytesInDmaPage(Addr curAddr, uint32_t bytesLeft);
343
344    /**
345     * Serialize this object to the given output stream.
346     * @param os The stream to serialize to.
347     */
348    void serialize(std::ostream &os);
349
350    /**
351     * Reconstruct the state of this object from a checkpoint.
352     * @param cp The checkpoint to use.
353     * @param section The section name describing this object.
354     */
355    void unserialize(Checkpoint *cp, const std::string &section);
356};
357
358
359#endif // __IDE_DISK_HH__
360