ide_disk.cc

来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· CC 代码 · 共 1,120 行 · 第 1/3 页

CC
1,120
字号
/* * Copyright (c) 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Andrew L. Schultz *          Ali G. Saidi *//** @file * Device model implementation for an IDE disk */#include <cerrno>#include <cstring>#include <deque>#include <string>#include "arch/isa_traits.hh"#include "base/chunk_generator.hh"#include "base/cprintf.hh" // csprintf#include "base/trace.hh"#include "dev/disk_image.hh"#include "dev/ide_ctrl.hh"#include "dev/ide_disk.hh"#include "sim/core.hh"#include "sim/sim_object.hh"using namespace std;using namespace TheISA;IdeDisk::IdeDisk(const Params *p)    : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay),      dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),      dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),      dmaReadEvent(this), dmaWriteEvent(this){    // Reset the device state    reset(p->driveID);    // fill out the drive ID structure    memset(&driveID, 0, sizeof(struct ataparams));    // Calculate LBA and C/H/S values    uint16_t cylinders;    uint8_t heads;    uint8_t sectors;    uint32_t lba_size = image->size();    if (lba_size >= 16383*16*63) {        cylinders = 16383;        heads = 16;        sectors = 63;    } else {        if (lba_size >= 63)            sectors = 63;        else            sectors = lba_size;        if ((lba_size / sectors) >= 16)            heads = 16;        else            heads = (lba_size / sectors);        cylinders = lba_size / (heads * sectors);    }    // Setup the model name    strncpy((char *)driveID.atap_model, "5MI EDD si k",            sizeof(driveID.atap_model));    // Set the maximum multisector transfer size    driveID.atap_multi = MAX_MULTSECT;    // IORDY supported, IORDY disabled, LBA enabled, DMA enabled    driveID.atap_capabilities1 = 0x7;    // UDMA support, EIDE support    driveID.atap_extensions = 0x6;    // Setup default C/H/S settings    driveID.atap_cylinders = cylinders;    driveID.atap_sectors = sectors;    driveID.atap_heads = heads;    // Setup the current multisector transfer size    driveID.atap_curmulti = MAX_MULTSECT;    driveID.atap_curmulti_valid = 0x1;    // Number of sectors on disk    driveID.atap_capacity = lba_size;    // Multiword DMA mode 2 and below supported    driveID.atap_dmamode_supp = 0x4;    // Set PIO mode 4 and 3 supported    driveID.atap_piomode_supp = 0x3;    // Set DMA mode 4 and below supported    driveID.atap_udmamode_supp = 0x1f;    // Statically set hardware config word    driveID.atap_hwreset_res = 0x4001;    //arbitrary for now...    driveID.atap_ata_major = WDC_VER_ATA7;}IdeDisk::~IdeDisk(){    // destroy the data buffer    delete [] dataBuffer;}voidIdeDisk::reset(int id){    // initialize the data buffer and shadow registers    dataBuffer = new uint8_t[MAX_DMA_SIZE];    memset(dataBuffer, 0, MAX_DMA_SIZE);    memset(&cmdReg, 0, sizeof(CommandReg_t));    memset(&curPrd.entry, 0, sizeof(PrdEntry_t));    curPrdAddr = 0;    curSector = 0;    cmdBytes = 0;    cmdBytesLeft = 0;    drqBytesLeft = 0;    dmaRead = false;    intrPending = false;    // set the device state to idle    dmaState = Dma_Idle;    if (id == DEV0) {        devState = Device_Idle_S;        devID = DEV0;    } else if (id == DEV1) {        devState = Device_Idle_NS;        devID = DEV1;    } else {        panic("Invalid device ID: %#x\n", id);    }    // set the device ready bit    status = STATUS_DRDY_BIT;    /* The error register must be set to 0x1 on start-up to       indicate that no diagnostic error was detected */    cmdReg.error = 0x1;}////// Utility functions////boolIdeDisk::isDEVSelect(){    return ctrl->isDiskSelected(this);}AddrIdeDisk::pciToDma(Addr pciAddr){    if (ctrl)        return ctrl->plat->pciToDma(pciAddr);    else        panic("Access to unset controller!\n");}////// Device registers read/write////voidIdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data){    DevAction_t action = ACT_NONE;    switch (reg_type) {      case COMMAND_BLOCK:        switch (offset) {          // Data transfers occur two bytes at a time          case DATA_OFFSET:            *(uint16_t*)data = cmdReg.data;            action = ACT_DATA_READ_SHORT;            break;          case ERROR_OFFSET:            *data = cmdReg.error;            break;          case NSECTOR_OFFSET:            *data = cmdReg.sec_count;            break;          case SECTOR_OFFSET:            *data = cmdReg.sec_num;            break;          case LCYL_OFFSET:            *data = cmdReg.cyl_low;            break;          case HCYL_OFFSET:            *data = cmdReg.cyl_high;            break;          case DRIVE_OFFSET:            *data = cmdReg.drive;            break;          case STATUS_OFFSET:            *data = status;            action = ACT_STAT_READ;            break;          default:            panic("Invalid IDE command register offset: %#x\n", offset);        }        break;      case CONTROL_BLOCK:        if (offset == ALTSTAT_OFFSET)            *data = status;        else            panic("Invalid IDE control register offset: %#x\n", offset);        break;      default:        panic("Unknown register block!\n");    }    DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset,            (uint32_t)*data);    if (action != ACT_NONE)        updateState(action);}voidIdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data){    DevAction_t action = ACT_NONE;    switch (reg_type) {      case COMMAND_BLOCK:        switch (offset) {          case DATA_OFFSET:            cmdReg.data = *(uint16_t*)data;            action = ACT_DATA_WRITE_SHORT;            break;          case FEATURES_OFFSET:            break;          case NSECTOR_OFFSET:            cmdReg.sec_count = *data;            break;          case SECTOR_OFFSET:            cmdReg.sec_num = *data;            break;          case LCYL_OFFSET:            cmdReg.cyl_low = *data;            break;          case HCYL_OFFSET:            cmdReg.cyl_high = *data;            break;          case DRIVE_OFFSET:            cmdReg.drive = *data;            action = ACT_SELECT_WRITE;            break;          case COMMAND_OFFSET:            cmdReg.command = *data;            action = ACT_CMD_WRITE;            break;          default:            panic("Invalid IDE command register offset: %#x\n", offset);        }        break;      case CONTROL_BLOCK:        if (offset == CONTROL_OFFSET) {            if (*data & CONTROL_RST_BIT) {                // force the device into the reset state                devState = Device_Srst;                action = ACT_SRST_SET;            } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT))                action = ACT_SRST_CLEAR;            nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;        }        else            panic("Invalid IDE control register offset: %#x\n", offset);        break;      default:        panic("Unknown register block!\n");    }    DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,            (uint32_t)*data);    if (action != ACT_NONE)        updateState(action);}////// Perform DMA transactions////voidIdeDisk::doDmaTransfer(){    if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)        panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",              dmaState, devState);    if (ctrl->dmaPending() || ctrl->getState() != SimObject::Running) {        dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);        return;    } else        ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,                (uint8_t*)&curPrd.entry);}voidIdeDisk::dmaPrdReadDone(){    DPRINTF(IdeDisk,            "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",            curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),            curPrd.getByteCount(), (cmdBytesLeft/SectorSize),            curPrd.getEOT(), curSector);    // the prd pointer has already been translated, so just do an increment    curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);    if (dmaRead)        doDmaDataRead();    else        doDmaDataWrite();}voidIdeDisk::doDmaDataRead(){    /** @todo we need to figure out what the delay actually will be */    Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);    DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",            diskDelay, totalDiskDelay);    dmaReadWaitEvent.schedule(curTick + totalDiskDelay);}voidIdeDisk::regStats(){    using namespace Stats;    dmaReadFullPages        .name(name() + ".dma_read_full_pages")        .desc("Number of full page size DMA reads (not PRD).")        ;    dmaReadBytes        .name(name() + ".dma_read_bytes")        .desc("Number of bytes transfered via DMA reads (not PRD).")        ;    dmaReadTxs        .name(name() + ".dma_read_txs")        .desc("Number of DMA read transactions (not PRD).")        ;    dmaWriteFullPages        .name(name() + ".dma_write_full_pages")        .desc("Number of full page size DMA writes.")

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?