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 + -
显示快捷键?