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