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