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