ide_disk.hh revision 896
1/* 2 * Copyright (c) 2003 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/ide.hh" 37#include "dev/disk_image.hh" 38#include "dev/io_device.hh" 39#include "sim/eventq.hh" 40 41#define DMA_BACKOFF_PERIOD 200 42 43#define MAX_DMA_SIZE (65536) // 64K 44#define MAX_MULTSECT (128) 45 46#define PRD_BASE_MASK 0xfffffffe 47#define PRD_COUNT_MASK 0xfffe 48#define PRD_EOT_MASK 0x8000 49 50typedef struct PrdEntry { 51 uint32_t baseAddr; 52 uint16_t byteCount; 53 uint16_t endOfTable; 54} PrdEntry_t; 55 56class PrdTableEntry { 57 public: 58 PrdEntry_t entry; 59 60 uint32_t getBaseAddr() 61 { 62 return (entry.baseAddr & PRD_BASE_MASK); 63 } 64 65 uint32_t getByteCount() 66 { 67 return ((entry.byteCount == 0) ? MAX_DMA_SIZE : 68 (entry.byteCount & PRD_COUNT_MASK)); 69 } 70 71 uint16_t getEOT() 72 { 73 return (entry.endOfTable & PRD_EOT_MASK); 74 } 75}; 76 77#define DATA_OFFSET (0) 78#define ERROR_OFFSET (1) 79#define FEATURES_OFFSET (1) 80#define NSECTOR_OFFSET (2) 81#define SECTOR_OFFSET (3) 82#define LCYL_OFFSET (4) 83#define HCYL_OFFSET (5) 84#define SELECT_OFFSET (6) 85#define STATUS_OFFSET (7) 86#define COMMAND_OFFSET (7) 87 88#define CONTROL_OFFSET (2) 89#define ALTSTAT_OFFSET (2) 90 91#define SELECT_DEV_BIT 0x10 92#define CONTROL_RST_BIT 0x04 93#define CONTROL_IEN_BIT 0x02 94#define STATUS_BSY_BIT 0x80 95#define STATUS_DRDY_BIT 0x40 96#define STATUS_DRQ_BIT 0x08 97#define STATUS_SEEK_BIT 0x10 98#define STATUS_DF_BIT 0x20 99#define DRIVE_LBA_BIT 0x40 100 101#define DEV0 (0) 102#define DEV1 (1) 103 104typedef struct CommandReg { 105 uint8_t data0; 106 union { 107 uint8_t data1; 108 uint8_t error; 109 uint8_t features; 110 }; 111 uint8_t sec_count; 112 uint8_t sec_num; 113 uint8_t cyl_low; 114 uint8_t cyl_high; 115 union { 116 uint8_t drive; 117 uint8_t head; 118 }; 119 uint8_t command; 120} CommandReg_t; 121 122typedef enum Events { 123 None = 0, 124 Transfer, 125 ReadWait, 126 WriteWait, 127 PrdRead, 128 DmaRead, 129 DmaWrite 130} Events_t; 131 132typedef enum DevAction { 133 ACT_NONE = 0, 134 ACT_CMD_WRITE, 135 ACT_CMD_COMPLETE, 136 ACT_CMD_ERROR, 137 ACT_SELECT_WRITE, 138 ACT_STAT_READ, 139 ACT_DATA_READY, 140 ACT_DATA_READ_BYTE, 141 ACT_DATA_READ_SHORT, 142 ACT_DATA_WRITE_BYTE, 143 ACT_DATA_WRITE_SHORT, 144 ACT_DMA_READY, 145 ACT_DMA_DONE, 146 ACT_SRST_SET, 147 ACT_SRST_CLEAR 148} DevAction_t; 149 150typedef enum DevState { 151 // Device idle 152 Device_Idle_S = 0, 153 Device_Idle_SI, 154 Device_Idle_NS, 155 156 // Software reset 157 Device_Srst, 158 159 // Non-data commands 160 Command_Execution, 161 162 // PIO data-in (data to host) 163 Prepare_Data_In, 164 Data_Ready_INTRQ_In, 165 Transfer_Data_In, 166 167 // PIO data-out (data from host) 168 Prepare_Data_Out, 169 Data_Ready_INTRQ_Out, 170 Transfer_Data_Out, 171 172 // DMA protocol 173 Prepare_Data_Dma, 174 Transfer_Data_Dma 175} DevState_t; 176 177typedef enum DmaState { 178 Dma_Idle = 0, 179 Dma_Start, 180 Dma_Transfer 181} DmaState_t; 182 183class PhysicalMemory; 184class IdeController; 185 186/** 187 * IDE Disk device model 188 */ 189class IdeDisk : public SimObject 190{ 191 protected: 192 /** The IDE controller for this disk. */ 193 IdeController *ctrl; 194 /** The DMA interface to use for transfers */ 195 DMAInterface<Bus> *dmaInterface; 196 /** The image that contains the data of this disk. */ 197 DiskImage *image; 198 /** Pointer to physical memory for DMA transfers */ 199 PhysicalMemory *physmem; 200 201 protected: 202 /** The disk delay in microseconds. */ 203 int diskDelay; 204 205 private: 206 /** Drive identification structure for this disk */ 207 struct hd_driveid driveID; 208 /** Data buffer for transfers */ 209 uint8_t *dataBuffer; 210 /** Number of bytes in command data transfer */ 211 uint32_t cmdBytes; 212 /** Number of bytes left in command data transfer */ 213 uint32_t cmdBytesLeft; 214 /** Number of bytes left in DRQ block */ 215 uint32_t drqBytesLeft; 216 /** Current sector in access */ 217 uint32_t curSector; 218 /** Command block registers */ 219 CommandReg_t cmdReg; 220 /** Status register */ 221 uint8_t status; 222 /** Interrupt enable bit */ 223 bool nIENBit; 224 /** Device state */ 225 DevState_t devState; 226 /** Dma state */ 227 DmaState_t dmaState; 228 /** Dma transaction is a read */ 229 bool dmaRead; 230 /** PRD table base address */ 231 uint32_t curPrdAddr; 232 /** PRD entry */ 233 PrdTableEntry curPrd; 234 /** Number of bytes transfered by DMA interface for current transfer */ 235 uint32_t dmaInterfaceBytes; 236 /** Device ID (master=0/slave=1) */ 237 int devID; 238 /** Interrupt pending */ 239 bool intrPending; 240 241 public: 242 /** 243 * Create and initialize this Disk. 244 * @param name The name of this disk. 245 * @param img The disk image of this disk. 246 * @param phys Pointer to physical memory 247 * @param id The disk ID (master=0/slave=1) 248 * @param disk_delay The disk delay in milliseconds 249 */ 250 IdeDisk(const std::string &name, DiskImage *img, PhysicalMemory *phys, 251 int id, int disk_delay); 252 253 /** 254 * Delete the data buffer. 255 */ 256 ~IdeDisk(); 257 258 /** 259 * Reset the device state 260 */ 261 void reset(int id); 262 263 /** 264 * Set the controller for this device 265 * @param c The IDE controller 266 */ 267 void setController(IdeController *c, DMAInterface<Bus> *dmaIntr) { 268 if (ctrl) panic("Cannot change the controller once set!\n"); 269 ctrl = c; 270 dmaInterface = dmaIntr; 271 } 272 273 // Device register read/write 274 void read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data); 275 void write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data); 276 277 // Start/abort functions 278 void startDma(const uint32_t &prdTableBase); 279 void abortDma(); 280 281 private: 282 void startCommand(); 283 284 // Interrupt management 285 void intrPost(); 286 void intrClear(); 287 288 // DMA stuff 289 void doDmaTransfer(); 290 friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>; 291 EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent; 292 293 void doDmaRead(); 294 friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>; 295 EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent; 296 297 void doDmaWrite(); 298 friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>; 299 EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent; 300 301 void dmaPrdReadDone(); 302 friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>; 303 EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent; 304 305 void dmaReadDone(); 306 friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>; 307 EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent; 308 309 void dmaWriteDone(); 310 friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>; 311 EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent; 312 313 // Disk image read/write 314 void readDisk(uint32_t sector, uint8_t *data); 315 void writeDisk(uint32_t sector, uint8_t *data); 316 317 // State machine management 318 void updateState(DevAction_t action); 319 320 // Utility functions 321 bool isBSYSet() { return (status & STATUS_BSY_BIT); } 322 bool isIENSet() { return nIENBit; } 323 bool isDEVSelect() { return ((cmdReg.drive & SELECT_DEV_BIT) == devID); } 324 325 void setComplete() 326 { 327 // clear out the status byte 328 status = 0; 329 // set the DRDY bit 330 status |= STATUS_DRDY_BIT; 331 // set the SEEK bit 332 status |= STATUS_SEEK_BIT; 333 } 334 335 uint32_t getLBABase() 336 { 337 return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) | 338 (cmdReg.cyl_low << 8) | (cmdReg.sec_num)); 339 } 340 341 inline Addr pciToDma(Addr pciAddr); 342 343 uint32_t bytesInDmaPage(Addr curAddr, uint32_t bytesLeft); 344 345 /** 346 * Serialize this object to the given output stream. 347 * @param os The stream to serialize to. 348 */ 349 void serialize(std::ostream &os); 350 351 /** 352 * Reconstruct the state of this object from a checkpoint. 353 * @param cp The checkpoint to use. 354 * @param section The section name describing this object. 355 */ 356 void unserialize(Checkpoint *cp, const std::string §ion); 357}; 358 359 360#endif // __IDE_DISK_HH__ 361