ide_disk.hh revision 5034
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 read(const Addr &offset, IdeRegType regtype, uint8_t *data); 282 void write(const Addr &offset, IdeRegType regtype, const uint8_t *data); 283 284 // Start/abort functions 285 void startDma(const uint32_t &prdTableBase); 286 void abortDma(); 287 288 private: 289 void startCommand(); 290 291 // Interrupt management 292 void intrPost(); 293 void intrClear(); 294 295 // DMA stuff 296 void doDmaTransfer(); 297 friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>; 298 EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent; 299 300 void doDmaDataRead(); 301 302 void doDmaRead(); 303 ChunkGenerator *dmaReadCG; 304 friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>; 305 EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent; 306 307 void doDmaDataWrite(); 308 309 void doDmaWrite(); 310 ChunkGenerator *dmaWriteCG; 311 friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>; 312 EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent; 313 314 void dmaPrdReadDone(); 315 friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>; 316 EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent; 317 318 void dmaReadDone(); 319 friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>; 320 EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent; 321 322 void dmaWriteDone(); 323 friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>; 324 EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent; 325 326 // Disk image read/write 327 void readDisk(uint32_t sector, uint8_t *data); 328 void writeDisk(uint32_t sector, uint8_t *data); 329 330 // State machine management 331 void updateState(DevAction_t action); 332 333 // Utility functions 334 bool isBSYSet() { return (status & STATUS_BSY_BIT); } 335 bool isIENSet() { return nIENBit; } 336 bool isDEVSelect(); 337 338 void setComplete() 339 { 340 // clear out the status byte 341 status = 0; 342 // set the DRDY bit 343 status |= STATUS_DRDY_BIT; 344 // set the SEEK bit 345 status |= STATUS_SEEK_BIT; 346 } 347 348 uint32_t getLBABase() 349 { 350 return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) | 351 (cmdReg.cyl_low << 8) | (cmdReg.sec_num)); 352 } 353 354 inline Addr pciToDma(Addr pciAddr); 355 356 /** 357 * Serialize this object to the given output stream. 358 * @param os The stream to serialize to. 359 */ 360 void serialize(std::ostream &os); 361 362 /** 363 * Reconstruct the state of this object from a checkpoint. 364 * @param cp The checkpoint to use. 365 * @param section The section name describing this object. 366 */ 367 void unserialize(Checkpoint *cp, const std::string §ion); 368}; 369 370 371#endif // __IDE_DISK_HH__ 372