ide_ctrl.cc

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

CC
754
字号
/* * 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 *          Miguel J. Serrano */#include <cstddef>#include <cstdlib>#include <string>#include <vector>#include "base/trace.hh"#include "cpu/intr_control.hh"#include "dev/ide_ctrl.hh"#include "dev/ide_disk.hh"#include "dev/pciconfigall.hh"#include "dev/pcireg.h"#include "dev/platform.hh"#include "mem/packet.hh"#include "mem/packet_access.hh"#include "params/IdeController.hh"#include "sim/sim_object.hh"#include "sim/byteswap.hh"using namespace std;////// Initialization and destruction////IdeController::IdeController(Params *p)    : PciDev(p){    // initialize the PIO interface addresses    pri_cmd_addr = 0;    pri_cmd_size = BARSize[0];    pri_ctrl_addr = 0;    pri_ctrl_size = BARSize[1];    sec_cmd_addr = 0;    sec_cmd_size = BARSize[2];    sec_ctrl_addr = 0;    sec_ctrl_size = BARSize[3];    // initialize the bus master interface (BMI) address to be configured    // via PCI    bmi_addr = 0;    bmi_size = BARSize[4];    // zero out all of the registers    memset(bmi_regs.data, 0, sizeof(bmi_regs));    memset(config_regs.data, 0, sizeof(config_regs.data));    // setup initial values    // enable both channels    config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN);    config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN);    bmi_regs.bmis0 = DMA1CAP | DMA0CAP;    bmi_regs.bmis1 = DMA1CAP | DMA0CAP;    // reset all internal variables    io_enabled = false;    bm_enabled = false;    memset(cmd_in_progress, 0, sizeof(cmd_in_progress));    // setup the disks attached to controller    memset(disks, 0, sizeof(disks));    dev[0] = 0;    dev[1] = 0;    if (params()->disks.size() > 3)        panic("IDE controllers support a maximum of 4 devices attached!\n");    for (int i = 0; i < params()->disks.size(); i++) {        disks[i] = params()->disks[i];        disks[i]->setController(this);    }}IdeController::~IdeController(){    for (int i = 0; i < 4; i++)        if (disks[i])            delete disks[i];}////// Utility functions///voidIdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,                         IdeRegType &reg_type){    offset = addr;    if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {        offset -= pri_cmd_addr;        reg_type = COMMAND_BLOCK;        channel = PRIMARY;    } else if (addr >= pri_ctrl_addr &&               addr < (pri_ctrl_addr + pri_ctrl_size)) {        offset -= pri_ctrl_addr;        reg_type = CONTROL_BLOCK;        channel = PRIMARY;    } else if (addr >= sec_cmd_addr &&               addr < (sec_cmd_addr + sec_cmd_size)) {        offset -= sec_cmd_addr;        reg_type = COMMAND_BLOCK;        channel = SECONDARY;    } else if (addr >= sec_ctrl_addr &&               addr < (sec_ctrl_addr + sec_ctrl_size)) {        offset -= sec_ctrl_addr;        reg_type = CONTROL_BLOCK;        channel = SECONDARY;    } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {        offset -= bmi_addr;        reg_type = BMI_BLOCK;        channel = (offset < BMIC1) ? PRIMARY : SECONDARY;    } else {        panic("IDE controller access to invalid address: %#x\n", addr);    }}intIdeController::getDisk(IdeChannel channel){    int disk = 0;    uint8_t *devBit = &dev[0];    if (channel == SECONDARY) {        disk += 2;        devBit = &dev[1];    }    disk += *devBit;    assert(*devBit == 0 || *devBit == 1);    return disk;}intIdeController::getDisk(IdeDisk *diskPtr){    for (int i = 0; i < 4; i++) {        if ((long)diskPtr == (long)disks[i])            return i;    }    return -1;}boolIdeController::isDiskSelected(IdeDisk *diskPtr){    for (int i = 0; i < 4; i++) {        if ((long)diskPtr == (long)disks[i]) {            // is disk is on primary or secondary channel            int channel = i/2;            // is disk the master or slave            int devID = i%2;            return (dev[channel] == devID);        }    }    panic("Unable to find disk by pointer!!\n");}////// Command completion////voidIdeController::setDmaComplete(IdeDisk *disk){    int diskNum = getDisk(disk);    if (diskNum < 0)        panic("Unable to find disk based on pointer %#x\n", disk);    if (diskNum < 2) {        // clear the start/stop bit in the command register        bmi_regs.bmic0 &= ~SSBM;        // clear the bus master active bit in the status register        bmi_regs.bmis0 &= ~BMIDEA;        // set the interrupt bit        bmi_regs.bmis0 |= IDEINTS;    } else {        // clear the start/stop bit in the command register        bmi_regs.bmic1 &= ~SSBM;        // clear the bus master active bit in the status register        bmi_regs.bmis1 &= ~BMIDEA;        // set the interrupt bit        bmi_regs.bmis1 |= IDEINTS;    }}////// Read and write handling////TickIdeController::readConfig(PacketPtr pkt){    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;    if (offset < PCI_DEVICE_SPECIFIC) {        return PciDev::readConfig(pkt);    }    assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);    pkt->allocate();    switch (pkt->getSize()) {      case sizeof(uint8_t):        switch (offset) {          case IDE_CTRL_CONF_DEV_TIMING:            pkt->set<uint8_t>(config_regs.sidetim);            break;          case IDE_CTRL_CONF_UDMA_CNTRL:            pkt->set<uint8_t>(config_regs.udmactl);            break;          case IDE_CTRL_CONF_PRIM_TIMING+1:            pkt->set<uint8_t>(htole(config_regs.idetim0) >> 8);            break;          case IDE_CTRL_CONF_SEC_TIMING+1:            pkt->set<uint8_t>(htole(config_regs.idetim1) >> 8);            break;          case IDE_CTRL_CONF_IDE_CONFIG:            pkt->set<uint8_t>(htole(config_regs.ideconfig) & 0xFF);            break;          case IDE_CTRL_CONF_IDE_CONFIG+1:            pkt->set<uint8_t>(htole(config_regs.ideconfig) >> 8);            break;          default:            panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",                    offset);        }        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,                (uint32_t)pkt->get<uint8_t>());        break;      case sizeof(uint16_t):        switch (offset) {          case IDE_CTRL_CONF_PRIM_TIMING:            pkt->set<uint16_t>(config_regs.idetim0);            break;          case IDE_CTRL_CONF_SEC_TIMING:            pkt->set<uint16_t>(config_regs.idetim1);            break;          case IDE_CTRL_CONF_UDMA_TIMING:            pkt->set<uint16_t>(config_regs.udmatim);            break;          case IDE_CTRL_CONF_IDE_CONFIG:            pkt->set<uint16_t>(config_regs.ideconfig);            break;          default:            panic("Invalid PCI configuration read for size 2 offset: %#x!\n",                    offset);        }        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,                (uint32_t)pkt->get<uint16_t>());        break;      case sizeof(uint32_t):        panic("No 32bit reads implemented for this device.");        DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,                (uint32_t)pkt->get<uint32_t>());        break;      default:        panic("invalid access size(?) for PCI configspace!\n");    }    pkt->makeAtomicResponse();    return configDelay;}TickIdeController::writeConfig(PacketPtr pkt){    int offset = pkt->getAddr() & PCI_CONFIG_SIZE;    if (offset < PCI_DEVICE_SPECIFIC) {        PciDev::writeConfig(pkt);    } else {        assert(offset >= IDE_CTRL_CONF_START && (offset + 1) <= IDE_CTRL_CONF_END);        switch (pkt->getSize()) {          case sizeof(uint8_t):            switch (offset) {              case IDE_CTRL_CONF_DEV_TIMING:                config_regs.sidetim = pkt->get<uint8_t>();                break;              case IDE_CTRL_CONF_UDMA_CNTRL:                config_regs.udmactl = pkt->get<uint8_t>();                break;              case IDE_CTRL_CONF_IDE_CONFIG:                config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) |                    (pkt->get<uint8_t>());                break;              case IDE_CTRL_CONF_IDE_CONFIG+1:                config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) |                    pkt->get<uint8_t>() << 8;                break;              default:                panic("Invalid PCI configuration write for size 1 offset: %#x!\n",                        offset);            }            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",                    offset, (uint32_t)pkt->get<uint8_t>());            break;          case sizeof(uint16_t):            switch (offset) {              case IDE_CTRL_CONF_PRIM_TIMING:                config_regs.idetim0 = pkt->get<uint16_t>();                break;              case IDE_CTRL_CONF_SEC_TIMING:                config_regs.idetim1 = pkt->get<uint16_t>();                break;              case IDE_CTRL_CONF_UDMA_TIMING:                config_regs.udmatim = pkt->get<uint16_t>();                break;              case IDE_CTRL_CONF_IDE_CONFIG:                config_regs.ideconfig = pkt->get<uint16_t>();                break;              default:                panic("Invalid PCI configuration write for size 2 offset: %#x!\n",                        offset);            }            DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",                    offset, (uint32_t)pkt->get<uint16_t>());            break;          case sizeof(uint32_t):            panic("Write of unimplemented PCI config. register: %x\n", offset);            break;          default:            panic("invalid access size(?) for PCI configspace!\n");        }        pkt->makeAtomicResponse();    }    /* Trap command register writes and enable IO/BM as appropriate as well as     * BARs. */    switch(offset) {      case PCI0_BASE_ADDR0:        if (BARAddrs[0] != 0)            pri_cmd_addr = BARAddrs[0];        break;      case PCI0_BASE_ADDR1:        if (BARAddrs[1] != 0)

⌨️ 快捷键说明

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