ide_disk.hh revision 2275
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 "base/statistics.hh" 37#include "dev/disk_image.hh" 38#include "dev/ide_atareg.h" 39#include "dev/ide_ctrl.hh" 40#include "dev/ide_wdcreg.h" 41#include "dev/io_device.hh" 42#include "sim/eventq.hh" 43 44#define DMA_BACKOFF_PERIOD 200 45 46#define MAX_DMA_SIZE (65536) // 64K 47#define MAX_MULTSECT (128) 48 49#define PRD_BASE_MASK 0xfffffffe 50#define PRD_COUNT_MASK 0xfffe 51#define PRD_EOT_MASK 0x8000 52 53typedef struct PrdEntry { 54 uint32_t baseAddr; 55 uint16_t byteCount; 56 uint16_t endOfTable; 57} PrdEntry_t; 58 59class PrdTableEntry { 60 public: 61 PrdEntry_t entry; 62 63 uint32_t getBaseAddr() 64 { 65 return (entry.baseAddr & PRD_BASE_MASK); 66 } 67 68 uint32_t getByteCount() 69 { 70 return ((entry.byteCount == 0) ? MAX_DMA_SIZE : 71 (entry.byteCount & PRD_COUNT_MASK)); 72 } 73 74 uint16_t getEOT() 75 { 76 return (entry.endOfTable & PRD_EOT_MASK); 77 } 78}; 79 80#define DATA_OFFSET (0) 81#define ERROR_OFFSET (1) 82#define FEATURES_OFFSET (1) 83#define NSECTOR_OFFSET (2) 84#define SECTOR_OFFSET (3) 85#define LCYL_OFFSET (4) 86#define HCYL_OFFSET (5) 87#define SELECT_OFFSET (6) 88#define DRIVE_OFFSET (6) 89#define STATUS_OFFSET (7) 90#define COMMAND_OFFSET (7) 91 92#define CONTROL_OFFSET (2) 93#define ALTSTAT_OFFSET (2) 94 95#define SELECT_DEV_BIT 0x10 96#define CONTROL_RST_BIT 0x04 97#define CONTROL_IEN_BIT 0x02 98#define STATUS_BSY_BIT 0x80 99#define STATUS_DRDY_BIT 0x40 100#define STATUS_DRQ_BIT 0x08 101#define STATUS_SEEK_BIT 0x10 102#define STATUS_DF_BIT 0x20 103#define DRIVE_LBA_BIT 0x40 104 105#define DEV0 (0) 106#define DEV1 (1) 107 108typedef struct CommandReg { 109 uint16_t data; 110 uint8_t error; 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 ataparams 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 Stats::Scalar<> dmaReadFullPages; 242 Stats::Scalar<> dmaReadBytes; 243 Stats::Scalar<> dmaReadTxs; 244 Stats::Scalar<> dmaWriteFullPages; 245 Stats::Scalar<> dmaWriteBytes; 246 Stats::Scalar<> dmaWriteTxs; 247 248 public: 249 /** 250 * Create and initialize this Disk. 251 * @param name The name of this disk. 252 * @param img The disk image of this disk. 253 * @param phys Pointer to physical memory 254 * @param id The disk ID (master=0/slave=1) 255 * @param disk_delay The disk delay in milliseconds 256 */ 257 IdeDisk(const std::string &name, DiskImage *img, PhysicalMemory *phys, 258 int id, Tick disk_delay); 259 260 /** 261 * Delete the data buffer. 262 */ 263 ~IdeDisk(); 264 265 /** 266 * Reset the device state 267 */ 268 void reset(int id); 269 270 /** 271 * Register statistics. 272 */ 273 void regStats(); 274 275 276 /** 277 * Set the controller for this device 278 * @param c The IDE controller 279 */ 280 void setController(IdeController *c, DMAInterface<Bus> *dmaIntr) { 281 if (ctrl) panic("Cannot change the controller once set!\n"); 282 ctrl = c; 283 dmaInterface = dmaIntr; 284 } 285 286 // Device register read/write 287 void read(const Addr &offset, IdeRegType regtype, uint8_t *data); 288 void write(const Addr &offset, IdeRegType regtype, const uint8_t *data); 289 290 // Start/abort functions 291 void startDma(const uint32_t &prdTableBase); 292 void abortDma(); 293 294 private: 295 void startCommand(); 296 297 // Interrupt management 298 void intrPost(); 299 void intrClear(); 300 301 // DMA stuff 302 void doDmaTransfer(); 303 friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>; 304 EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent; 305 306 void doDmaRead(); 307 friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>; 308 EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent; 309 310 void doDmaWrite(); 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 uint32_t bytesInDmaPage(Addr curAddr, uint32_t bytesLeft); 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