/* * Copyright (c) 2013 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall * not be construed as granting a license to any other intellectual * property including but not limited to intellectual property relating * to a hardware implementation of the functionality of the software * licensed hereunder. You may use the software subject to the license * terms below provided that you ensure that this notice is replicated * unmodified and in its entirety in all distributions of the software, * modified or unmodified, in source code or in binary form. * * Copyright (c) 2004-2005 The Regents of The University of Michigan * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Andrew Schultz */ /** @file * Device model for an IDE disk */ #ifndef __DEV_STORAGE_IDE_DISK_HH__ #define __DEV_STORAGE_IDE_DISK_HH__ #include "base/statistics.hh" #include "dev/io_device.hh" #include "dev/storage/disk_image.hh" #include "dev/storage/ide_atareg.h" #include "dev/storage/ide_ctrl.hh" #include "dev/storage/ide_wdcreg.h" #include "params/IdeDisk.hh" #include "sim/eventq.hh" class ChunkGenerator; #define DMA_BACKOFF_PERIOD 200 #define MAX_DMA_SIZE 0x20000 // 128K #define MAX_SINGLE_DMA_SIZE 0x10000 #define MAX_MULTSECT (128) #define PRD_BASE_MASK 0xfffffffe #define PRD_COUNT_MASK 0xfffe #define PRD_EOT_MASK 0x8000 typedef struct PrdEntry { uint32_t baseAddr; uint16_t byteCount; uint16_t endOfTable; } PrdEntry_t; class PrdTableEntry { public: PrdEntry_t entry; uint32_t getBaseAddr() { return (entry.baseAddr & PRD_BASE_MASK); } uint32_t getByteCount() { return ((entry.byteCount == 0) ? MAX_SINGLE_DMA_SIZE : (entry.byteCount & PRD_COUNT_MASK)); } uint16_t getEOT() { return (entry.endOfTable & PRD_EOT_MASK); } }; #define DATA_OFFSET (0) #define ERROR_OFFSET (1) #define FEATURES_OFFSET (1) #define NSECTOR_OFFSET (2) #define SECTOR_OFFSET (3) #define LCYL_OFFSET (4) #define HCYL_OFFSET (5) #define SELECT_OFFSET (6) #define DRIVE_OFFSET (6) #define STATUS_OFFSET (7) #define COMMAND_OFFSET (7) #define CONTROL_OFFSET (2) #define ALTSTAT_OFFSET (2) #define SELECT_DEV_BIT 0x10 #define CONTROL_RST_BIT 0x04 #define CONTROL_IEN_BIT 0x02 #define STATUS_BSY_BIT 0x80 #define STATUS_DRDY_BIT 0x40 #define STATUS_DRQ_BIT 0x08 #define STATUS_SEEK_BIT 0x10 #define STATUS_DF_BIT 0x20 #define DRIVE_LBA_BIT 0x40 #define DEV0 (0) #define DEV1 (1) typedef struct CommandReg { uint16_t data; uint8_t error; uint8_t sec_count; uint8_t sec_num; uint8_t cyl_low; uint8_t cyl_high; union { uint8_t drive; uint8_t head; }; uint8_t command; } CommandReg_t; typedef enum Events { None = 0, Transfer, ReadWait, WriteWait, PrdRead, DmaRead, DmaWrite } Events_t; typedef enum DevAction { ACT_NONE = 0, ACT_CMD_WRITE, ACT_CMD_COMPLETE, ACT_CMD_ERROR, ACT_SELECT_WRITE, ACT_STAT_READ, ACT_DATA_READY, ACT_DATA_READ_BYTE, ACT_DATA_READ_SHORT, ACT_DATA_WRITE_BYTE, ACT_DATA_WRITE_SHORT, ACT_DMA_READY, ACT_DMA_DONE, ACT_SRST_SET, ACT_SRST_CLEAR } DevAction_t; typedef enum DevState { // Device idle Device_Idle_S = 0, Device_Idle_SI, Device_Idle_NS, // Software reset Device_Srst, // Non-data commands Command_Execution, // PIO data-in (data to host) Prepare_Data_In, Data_Ready_INTRQ_In, Transfer_Data_In, // PIO data-out (data from host) Prepare_Data_Out, Data_Ready_INTRQ_Out, Transfer_Data_Out, // DMA protocol Prepare_Data_Dma, Transfer_Data_Dma, Device_Dma_Abort } DevState_t; typedef enum DmaState { Dma_Idle = 0, Dma_Start, Dma_Transfer } DmaState_t; class IdeController; /** * IDE Disk device model */ class IdeDisk : public SimObject { protected: /** The IDE controller for this disk. */ IdeController *ctrl; /** The image that contains the data of this disk. */ DiskImage *image; protected: /** The disk delay in microseconds. */ int diskDelay; private: /** Drive identification structure for this disk */ struct ataparams driveID; /** Data buffer for transfers */ uint8_t *dataBuffer; /** Number of bytes in command data transfer */ uint32_t cmdBytes; /** Number of bytes left in command data transfer */ uint32_t cmdBytesLeft; /** Number of bytes left in DRQ block */ uint32_t drqBytesLeft; /** Current sector in access */ uint32_t curSector; /** Command block registers */ CommandReg_t cmdReg; /** Status register */ uint8_t status; /** Interrupt enable bit */ bool nIENBit; /** Device state */ DevState_t devState; /** Dma state */ DmaState_t dmaState; /** Dma transaction is a read */ bool dmaRead; /** PRD table base address */ uint32_t curPrdAddr; /** PRD entry */ PrdTableEntry curPrd; /** Device ID (master=0/slave=1) */ int devID; /** Interrupt pending */ bool intrPending; /** DMA Aborted */ bool dmaAborted; Stats::Scalar dmaReadFullPages; Stats::Scalar dmaReadBytes; Stats::Scalar dmaReadTxs; Stats::Scalar dmaWriteFullPages; Stats::Scalar dmaWriteBytes; Stats::Scalar dmaWriteTxs; public: typedef IdeDiskParams Params; IdeDisk(const Params *p); /** * Delete the data buffer. */ ~IdeDisk(); /** * Reset the device state */ void reset(int id); /** * Register Statistics */ void regStats() override; /** * Set the controller for this device * @param c The IDE controller */ void setController(IdeController *c) { if (ctrl) panic("Cannot change the controller once set!\n"); ctrl = c; } // Device register read/write void readCommand(const Addr offset, int size, uint8_t *data); void readControl(const Addr offset, int size, uint8_t *data); void writeCommand(const Addr offset, int size, const uint8_t *data); void writeControl(const Addr offset, int size, const uint8_t *data); // Start/abort functions void startDma(const uint32_t &prdTableBase); void abortDma(); private: void startCommand(); // Interrupt management void intrPost(); void intrClear(); // DMA stuff void doDmaTransfer(); EventFunctionWrapper dmaTransferEvent; void doDmaDataRead(); void doDmaRead(); ChunkGenerator *dmaReadCG; EventFunctionWrapper dmaReadWaitEvent; void doDmaDataWrite(); void doDmaWrite(); ChunkGenerator *dmaWriteCG; EventFunctionWrapper dmaWriteWaitEvent; void dmaPrdReadDone(); EventFunctionWrapper dmaPrdReadEvent; void dmaReadDone(); EventFunctionWrapper dmaReadEvent; void dmaWriteDone(); EventFunctionWrapper dmaWriteEvent; // Disk image read/write void readDisk(uint32_t sector, uint8_t *data); void writeDisk(uint32_t sector, uint8_t *data); // State machine management void updateState(DevAction_t action); // Utility functions bool isBSYSet() { return (status & STATUS_BSY_BIT); } bool isIENSet() { return nIENBit; } bool isDEVSelect(); void setComplete() { // clear out the status byte status = 0; // set the DRDY bit status |= STATUS_DRDY_BIT; // set the SEEK bit status |= STATUS_SEEK_BIT; } uint32_t getLBABase() { return (Addr)(((cmdReg.head & 0xf) << 24) | (cmdReg.cyl_high << 16) | (cmdReg.cyl_low << 8) | (cmdReg.sec_num)); } inline Addr pciToDma(Addr pciAddr); void serialize(CheckpointOut &cp) const override; void unserialize(CheckpointIn &cp) override; }; #endif // __DEV_STORAGE_IDE_DISK_HH__