ide_disk.hh revision 1817
12810SN/A/* 29546Sandreas.hansson@arm.com * Copyright (c) 2004-2005 The Regents of The University of Michigan 39546Sandreas.hansson@arm.com * All rights reserved. 49546Sandreas.hansson@arm.com * 59546Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without 69546Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are 79546Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright 89546Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer; 99546Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright 109546Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the 119546Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution; 129546Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its 139546Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from 142810SN/A * this software without specific prior written permission. 152810SN/A * 162810SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172810SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182810SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192810SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202810SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212810SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222810SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232810SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242810SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252810SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262810SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272810SN/A */ 282810SN/A 292810SN/A/** @file 302810SN/A * Device model for an IDE disk 312810SN/A */ 322810SN/A 332810SN/A#ifndef __IDE_DISK_HH__ 342810SN/A#define __IDE_DISK_HH__ 352810SN/A 362810SN/A#include "dev/disk_image.hh" 372810SN/A#include "dev/ide_atareg.h" 382810SN/A#include "dev/ide_ctrl.hh" 392810SN/A#include "dev/ide_wdcreg.h" 402810SN/A#include "dev/io_device.hh" 412810SN/A#include "sim/eventq.hh" 422810SN/A 432810SN/A#define DMA_BACKOFF_PERIOD 200 442810SN/A 452810SN/A#define MAX_DMA_SIZE (65536) // 64K 462810SN/A#define MAX_MULTSECT (128) 472810SN/A 486658Snate@binkert.org#define PRD_BASE_MASK 0xfffffffe 496658Snate@binkert.org#define PRD_COUNT_MASK 0xfffe 505875Ssteve.reinhardt@amd.com#define PRD_EOT_MASK 0x8000 512810SN/A 526658Snate@binkert.orgtypedef struct PrdEntry { 538232Snate@binkert.org uint32_t baseAddr; 548229Snate@binkert.org uint16_t byteCount; 555338Sstever@gmail.com uint16_t endOfTable; 562814SN/A} PrdEntry_t; 578832SAli.Saidi@ARM.com 582810SN/Aclass PrdTableEntry { 598831Smrinmoy.ghosh@arm.com public: 609288Sandreas.hansson@arm.com PrdEntry_t entry; 618832SAli.Saidi@ARM.com 628832SAli.Saidi@ARM.com uint32_t getBaseAddr() 638832SAli.Saidi@ARM.com { 642810SN/A return (entry.baseAddr & PRD_BASE_MASK); 652810SN/A } 662810SN/A 672810SN/A uint32_t getByteCount() 682810SN/A { 692810SN/A return ((entry.byteCount == 0) ? MAX_DMA_SIZE : 702810SN/A (entry.byteCount & PRD_COUNT_MASK)); 712810SN/A } 722810SN/A 732810SN/A uint16_t getEOT() 742810SN/A { 758831Smrinmoy.ghosh@arm.com return (entry.endOfTable & PRD_EOT_MASK); 762810SN/A } 772810SN/A}; 788831Smrinmoy.ghosh@arm.com 792810SN/A#define DATA_OFFSET (0) 802810SN/A#define ERROR_OFFSET (1) 812810SN/A#define FEATURES_OFFSET (1) 822810SN/A#define NSECTOR_OFFSET (2) 838831Smrinmoy.ghosh@arm.com#define SECTOR_OFFSET (3) 842810SN/A#define LCYL_OFFSET (4) 852810SN/A#define HCYL_OFFSET (5) 862810SN/A#define SELECT_OFFSET (6) 872810SN/A#define DRIVE_OFFSET (6) 888831Smrinmoy.ghosh@arm.com#define STATUS_OFFSET (7) 892810SN/A#define COMMAND_OFFSET (7) 902810SN/A 912810SN/A#define CONTROL_OFFSET (2) 922810SN/A#define ALTSTAT_OFFSET (2) 938831Smrinmoy.ghosh@arm.com 942810SN/A#define SELECT_DEV_BIT 0x10 952810SN/A#define CONTROL_RST_BIT 0x04 962810SN/A#define CONTROL_IEN_BIT 0x02 972810SN/A#define STATUS_BSY_BIT 0x80 988831Smrinmoy.ghosh@arm.com#define STATUS_DRDY_BIT 0x40 992810SN/A#define STATUS_DRQ_BIT 0x08 1002810SN/A#define STATUS_SEEK_BIT 0x10 1012810SN/A#define STATUS_DF_BIT 0x20 1022810SN/A#define DRIVE_LBA_BIT 0x40 1038831Smrinmoy.ghosh@arm.com 1042810SN/A#define DEV0 (0) 1052810SN/A#define DEV1 (1) 1062810SN/A 1072810SN/Atypedef struct CommandReg { 1088831Smrinmoy.ghosh@arm.com uint16_t data; 1092810SN/A uint8_t error; 1102810SN/A uint8_t sec_count; 1112810SN/A uint8_t sec_num; 1122810SN/A uint8_t cyl_low; 1138831Smrinmoy.ghosh@arm.com uint8_t cyl_high; 1142810SN/A union { 1152810SN/A uint8_t drive; 1162810SN/A uint8_t head; 1172810SN/A }; 1188831Smrinmoy.ghosh@arm.com uint8_t command; 1195875Ssteve.reinhardt@amd.com} CommandReg_t; 1205875Ssteve.reinhardt@amd.com 1212810SN/Atypedef enum Events { 1222810SN/A None = 0, 1232810SN/A Transfer, 1243861SN/A ReadWait, 1253861SN/A WriteWait, 1263861SN/A PrdRead, 1273861SN/A DmaRead, 1283861SN/A DmaWrite 1293861SN/A} Events_t; 1303861SN/A 1313861SN/Atypedef enum DevAction { 1323861SN/A ACT_NONE = 0, 1333861SN/A ACT_CMD_WRITE, 1343861SN/A ACT_CMD_COMPLETE, 1353861SN/A ACT_CMD_ERROR, 1363861SN/A ACT_SELECT_WRITE, 1373861SN/A ACT_STAT_READ, 1383861SN/A ACT_DATA_READY, 1393861SN/A ACT_DATA_READ_BYTE, 1403861SN/A ACT_DATA_READ_SHORT, 1413861SN/A ACT_DATA_WRITE_BYTE, 1423861SN/A ACT_DATA_WRITE_SHORT, 1433861SN/A ACT_DMA_READY, 1443349SN/A ACT_DMA_DONE, 1452810SN/A ACT_SRST_SET, 1462810SN/A ACT_SRST_CLEAR 1475875Ssteve.reinhardt@amd.com} DevAction_t; 1482810SN/A 1492810SN/Atypedef enum DevState { 1505875Ssteve.reinhardt@amd.com // Device idle 1512810SN/A Device_Idle_S = 0, 1522810SN/A Device_Idle_SI, 1532810SN/A Device_Idle_NS, 1549546Sandreas.hansson@arm.com 1558509SAli.Saidi@ARM.com // Software reset 1569546Sandreas.hansson@arm.com Device_Srst, 1572810SN/A 1585875Ssteve.reinhardt@amd.com // Non-data commands 1598509SAli.Saidi@ARM.com Command_Execution, 1608509SAli.Saidi@ARM.com 1618509SAli.Saidi@ARM.com // PIO data-in (data to host) 1628509SAli.Saidi@ARM.com Prepare_Data_In, 1638509SAli.Saidi@ARM.com Data_Ready_INTRQ_In, 1648509SAli.Saidi@ARM.com Transfer_Data_In, 1658509SAli.Saidi@ARM.com 1668509SAli.Saidi@ARM.com // PIO data-out (data from host) 1678509SAli.Saidi@ARM.com Prepare_Data_Out, 1685875Ssteve.reinhardt@amd.com Data_Ready_INTRQ_Out, 1692810SN/A Transfer_Data_Out, 1704628SN/A 1718509SAli.Saidi@ARM.com // DMA protocol 1722810SN/A Prepare_Data_Dma, 1738509SAli.Saidi@ARM.com Transfer_Data_Dma 1742810SN/A} DevState_t; 1752810SN/A 1765875Ssteve.reinhardt@amd.comtypedef enum DmaState { 1775875Ssteve.reinhardt@amd.com Dma_Idle = 0, 1782810SN/A Dma_Start, 1792810SN/A Dma_Transfer 1802810SN/A} DmaState_t; 1815875Ssteve.reinhardt@amd.com 1825875Ssteve.reinhardt@amd.comclass PhysicalMemory; 1839546Sandreas.hansson@arm.comclass IdeController; 1842810SN/A 1856105Ssteve.reinhardt@amd.com/** 1865875Ssteve.reinhardt@amd.com * IDE Disk device model 1875875Ssteve.reinhardt@amd.com */ 1882810SN/Aclass IdeDisk : public SimObject 1895875Ssteve.reinhardt@amd.com{ 1909546Sandreas.hansson@arm.com protected: 1912810SN/A /** The IDE controller for this disk. */ 1925875Ssteve.reinhardt@amd.com IdeController *ctrl; 1935875Ssteve.reinhardt@amd.com /** The DMA interface to use for transfers */ 1942810SN/A DMAInterface<Bus> *dmaInterface; 1959546Sandreas.hansson@arm.com /** The image that contains the data of this disk. */ 1969546Sandreas.hansson@arm.com DiskImage *image; 1978991SAli.Saidi@ARM.com /** Pointer to physical memory for DMA transfers */ 1982810SN/A PhysicalMemory *physmem; 1994628SN/A 2002810SN/A protected: 2012810SN/A /** The disk delay in microseconds. */ 2025875Ssteve.reinhardt@amd.com int diskDelay; 2035875Ssteve.reinhardt@amd.com 2045875Ssteve.reinhardt@amd.com private: 2055875Ssteve.reinhardt@amd.com /** Drive identification structure for this disk */ 2065875Ssteve.reinhardt@amd.com struct ataparams driveID; 2072810SN/A /** Data buffer for transfers */ 2082810SN/A uint8_t *dataBuffer; 2098991SAli.Saidi@ARM.com /** Number of bytes in command data transfer */ 2108991SAli.Saidi@ARM.com uint32_t cmdBytes; 2119546Sandreas.hansson@arm.com /** Number of bytes left in command data transfer */ 2122810SN/A uint32_t cmdBytesLeft; 2135875Ssteve.reinhardt@amd.com /** Number of bytes left in DRQ block */ 2149546Sandreas.hansson@arm.com uint32_t drqBytesLeft; 2159546Sandreas.hansson@arm.com /** Current sector in access */ 2169546Sandreas.hansson@arm.com uint32_t curSector; 2178991SAli.Saidi@ARM.com /** Command block registers */ 2188991SAli.Saidi@ARM.com CommandReg_t cmdReg; 2198991SAli.Saidi@ARM.com /** Status register */ 2202810SN/A uint8_t status; 2212810SN/A /** Interrupt enable bit */ 2224628SN/A bool nIENBit; 2232810SN/A /** Device state */ 2242810SN/A DevState_t devState; 2252810SN/A /** Dma state */ 2262810SN/A DmaState_t dmaState; 2279288Sandreas.hansson@arm.com /** Dma transaction is a read */ 2282810SN/A bool dmaRead; 2292810SN/A /** PRD table base address */ 2305875Ssteve.reinhardt@amd.com uint32_t curPrdAddr; 2319288Sandreas.hansson@arm.com /** PRD entry */ 2325875Ssteve.reinhardt@amd.com PrdTableEntry curPrd; 2335875Ssteve.reinhardt@amd.com /** Number of bytes transfered by DMA interface for current transfer */ 2345875Ssteve.reinhardt@amd.com uint32_t dmaInterfaceBytes; 2352810SN/A /** Device ID (master=0/slave=1) */ 2365875Ssteve.reinhardt@amd.com int devID; 2375875Ssteve.reinhardt@amd.com /** Interrupt pending */ 2385875Ssteve.reinhardt@amd.com bool intrPending; 2395875Ssteve.reinhardt@amd.com 2405875Ssteve.reinhardt@amd.com public: 2415875Ssteve.reinhardt@amd.com /** 2425875Ssteve.reinhardt@amd.com * Create and initialize this Disk. 2435875Ssteve.reinhardt@amd.com * @param name The name of this disk. 2445875Ssteve.reinhardt@amd.com * @param img The disk image of this disk. 2455875Ssteve.reinhardt@amd.com * @param phys Pointer to physical memory 2465875Ssteve.reinhardt@amd.com * @param id The disk ID (master=0/slave=1) 2475875Ssteve.reinhardt@amd.com * @param disk_delay The disk delay in milliseconds 2485875Ssteve.reinhardt@amd.com */ 2498832SAli.Saidi@ARM.com IdeDisk(const std::string &name, DiskImage *img, PhysicalMemory *phys, 2505875Ssteve.reinhardt@amd.com int id, Tick disk_delay); 2518949Sandreas.hansson@arm.com 2522825SN/A /** 2535714Shsul@eecs.umich.edu * Delete the data buffer. 2545714Shsul@eecs.umich.edu */ 2552814SN/A ~IdeDisk(); 2565875Ssteve.reinhardt@amd.com 2575875Ssteve.reinhardt@amd.com /** 2582810SN/A * Reset the device state 2599546Sandreas.hansson@arm.com */ 2605875Ssteve.reinhardt@amd.com void reset(int id); 2615875Ssteve.reinhardt@amd.com 2625875Ssteve.reinhardt@amd.com /** 2635875Ssteve.reinhardt@amd.com * Set the controller for this device 2642810SN/A * @param c The IDE controller 2652810SN/A */ 2662810SN/A void setController(IdeController *c, DMAInterface<Bus> *dmaIntr) { 2679546Sandreas.hansson@arm.com if (ctrl) panic("Cannot change the controller once set!\n"); 2689546Sandreas.hansson@arm.com ctrl = c; 2692810SN/A dmaInterface = dmaIntr; 2702810SN/A } 2715875Ssteve.reinhardt@amd.com 2729546Sandreas.hansson@arm.com // Device register read/write 2732810SN/A void read(const Addr &offset, IdeRegType regtype, uint8_t *data); 2742810SN/A void write(const Addr &offset, IdeRegType regtype, const uint8_t *data); 2759546Sandreas.hansson@arm.com 2762810SN/A // Start/abort functions 2772810SN/A void startDma(const uint32_t &prdTableBase); 2785875Ssteve.reinhardt@amd.com void abortDma(); 2799546Sandreas.hansson@arm.com 2805875Ssteve.reinhardt@amd.com private: 2819546Sandreas.hansson@arm.com void startCommand(); 2822810SN/A 2832810SN/A // Interrupt management 2842810SN/A void intrPost(); 2852810SN/A void intrClear(); 2862810SN/A 2872810SN/A // DMA stuff 2885875Ssteve.reinhardt@amd.com void doDmaTransfer(); 2895875Ssteve.reinhardt@amd.com friend class EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer>; 2905875Ssteve.reinhardt@amd.com EventWrapper<IdeDisk, &IdeDisk::doDmaTransfer> dmaTransferEvent; 2915875Ssteve.reinhardt@amd.com 2925875Ssteve.reinhardt@amd.com void doDmaRead(); 2938831Smrinmoy.ghosh@arm.com friend class EventWrapper<IdeDisk, &IdeDisk::doDmaRead>; 2948831Smrinmoy.ghosh@arm.com EventWrapper<IdeDisk, &IdeDisk::doDmaRead> dmaReadWaitEvent; 295 296 void doDmaWrite(); 297 friend class EventWrapper<IdeDisk, &IdeDisk::doDmaWrite>; 298 EventWrapper<IdeDisk, &IdeDisk::doDmaWrite> dmaWriteWaitEvent; 299 300 void dmaPrdReadDone(); 301 friend class EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone>; 302 EventWrapper<IdeDisk, &IdeDisk::dmaPrdReadDone> dmaPrdReadEvent; 303 304 void dmaReadDone(); 305 friend class EventWrapper<IdeDisk, &IdeDisk::dmaReadDone>; 306 EventWrapper<IdeDisk, &IdeDisk::dmaReadDone> dmaReadEvent; 307 308 void dmaWriteDone(); 309 friend class EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone>; 310 EventWrapper<IdeDisk, &IdeDisk::dmaWriteDone> dmaWriteEvent; 311 312 // Disk image read/write 313 void readDisk(uint32_t sector, uint8_t *data); 314 void writeDisk(uint32_t sector, uint8_t *data); 315 316 // State machine management 317 void updateState(DevAction_t action); 318 319 // Utility functions 320 bool isBSYSet() { return (status & STATUS_BSY_BIT); } 321 bool isIENSet() { return nIENBit; } 322 bool isDEVSelect(); 323 324 void setComplete() 325 { 326 // clear out the status byte 327 status = 0; 328 // set the DRDY bit 329 status |= STATUS_DRDY_BIT; 330 // set the SEEK bit 331 status |= STATUS_SEEK_BIT; 332 } 333 334 uint32_t getLBABase() 335 { 336 return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) | 337 (cmdReg.cyl_low << 8) | (cmdReg.sec_num)); 338 } 339 340 inline Addr pciToDma(Addr pciAddr); 341 342 uint32_t bytesInDmaPage(Addr curAddr, uint32_t bytesLeft); 343 344 /** 345 * Serialize this object to the given output stream. 346 * @param os The stream to serialize to. 347 */ 348 void serialize(std::ostream &os); 349 350 /** 351 * Reconstruct the state of this object from a checkpoint. 352 * @param cp The checkpoint to use. 353 * @param section The section name describing this object. 354 */ 355 void unserialize(Checkpoint *cp, const std::string §ion); 356}; 357 358 359#endif // __IDE_DISK_HH__ 360