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