ide_ctrl.cc

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

CC
754
字号
            pri_ctrl_addr = BARAddrs[1];        break;      case PCI0_BASE_ADDR2:        if (BARAddrs[2] != 0)            sec_cmd_addr = BARAddrs[2];        break;      case PCI0_BASE_ADDR3:        if (BARAddrs[3] != 0)            sec_ctrl_addr = BARAddrs[3];        break;      case PCI0_BASE_ADDR4:        if (BARAddrs[4] != 0)            bmi_addr = BARAddrs[4];        break;      case PCI_COMMAND:        if (letoh(config.command) & PCI_CMD_IOSE)            io_enabled = true;        else            io_enabled = false;        if (letoh(config.command) & PCI_CMD_BME)            bm_enabled = true;        else            bm_enabled = false;        break;    }    return configDelay;}TickIdeController::read(PacketPtr pkt){    Addr offset;    IdeChannel channel;    IdeRegType reg_type;    int disk;    pkt->allocate();    if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)         panic("Bad IDE read size: %d\n", pkt->getSize());    parseAddr(pkt->getAddr(), offset, channel, reg_type);    if (!io_enabled) {        pkt->makeAtomicResponse();        return pioDelay;    }    switch (reg_type) {      case BMI_BLOCK:        switch (pkt->getSize()) {          case sizeof(uint8_t):            pkt->set(bmi_regs.data[offset]);            break;          case sizeof(uint16_t):            pkt->set(*(uint16_t*)&bmi_regs.data[offset]);            break;          case sizeof(uint32_t):            pkt->set(*(uint32_t*)&bmi_regs.data[offset]);            break;          default:            panic("IDE read of BMI reg invalid size: %#x\n", pkt->getSize());        }        break;      case COMMAND_BLOCK:      case CONTROL_BLOCK:        disk = getDisk(channel);        if (disks[disk] == NULL) {            pkt->set<uint8_t>(0);            break;        }        switch (offset) {          case DATA_OFFSET:            switch (pkt->getSize()) {              case sizeof(uint16_t):                disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());                break;              case sizeof(uint32_t):                disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());                disks[disk]->read(offset, reg_type,                        pkt->getPtr<uint8_t>() + sizeof(uint16_t));                break;              default:                panic("IDE read of data reg invalid size: %#x\n", pkt->getSize());            }            break;          default:            if (pkt->getSize() == sizeof(uint8_t)) {                disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());            } else                panic("IDE read of command reg of invalid size: %#x\n", pkt->getSize());        }        break;      default:        panic("IDE controller read of unknown register block type!\n");    }    if (pkt->getSize() == 1)    DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",            offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>());    else if (pkt->getSize() == 2)    DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",            offset, pkt->getSize(), pkt->get<uint16_t>());    else    DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",            offset, pkt->getSize(), pkt->get<uint32_t>());    pkt->makeAtomicResponse();    return pioDelay;}TickIdeController::write(PacketPtr pkt){    Addr offset;    IdeChannel channel;    IdeRegType reg_type;    int disk;    uint8_t oldVal, newVal;    parseAddr(pkt->getAddr(), offset, channel, reg_type);    if (!io_enabled) {        pkt->makeAtomicResponse();        DPRINTF(IdeCtrl, "io not enabled\n");        return pioDelay;    }    switch (reg_type) {      case BMI_BLOCK:        if (!bm_enabled) {            pkt->makeAtomicResponse();            return pioDelay;        }        switch (offset) {            // Bus master IDE command register          case BMIC1:          case BMIC0:            if (pkt->getSize() != sizeof(uint8_t))                panic("Invalid BMIC write size: %x\n", pkt->getSize());            // select the current disk based on DEV bit            disk = getDisk(channel);            oldVal = bmi_regs.chan[channel].bmic;            newVal = pkt->get<uint8_t>();            // if a DMA transfer is in progress, R/W control cannot change            if (oldVal & SSBM) {                if ((oldVal & RWCON) ^ (newVal & RWCON)) {                    (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON;                }            }            // see if the start/stop bit is being changed            if ((oldVal & SSBM) ^ (newVal & SSBM)) {                if (oldVal & SSBM) {                    // stopping DMA transfer                    DPRINTF(IdeCtrl, "Stopping DMA transfer\n");                    // clear the BMIDEA bit                    bmi_regs.chan[channel].bmis =                        bmi_regs.chan[channel].bmis & ~BMIDEA;                    if (disks[disk] == NULL)                        panic("DMA stop for disk %d which does not exist\n",                              disk);                    // inform the disk of the DMA transfer abort                    disks[disk]->abortDma();                } else {                    // starting DMA transfer                    DPRINTF(IdeCtrl, "Starting DMA transfer\n");                    // set the BMIDEA bit                    bmi_regs.chan[channel].bmis =                        bmi_regs.chan[channel].bmis | BMIDEA;                    if (disks[disk] == NULL)                        panic("DMA start for disk %d which does not exist\n",                              disk);                    // inform the disk of the DMA transfer start                    disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp));                }            }            // update the register value            bmi_regs.chan[channel].bmic = newVal;            break;            // Bus master IDE status register          case BMIS0:          case BMIS1:            if (pkt->getSize() != sizeof(uint8_t))                panic("Invalid BMIS write size: %x\n", pkt->getSize());            oldVal = bmi_regs.chan[channel].bmis;            newVal = pkt->get<uint8_t>();            // the BMIDEA bit is RO            newVal |= (oldVal & BMIDEA);            // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each            if ((oldVal & IDEINTS) && (newVal & IDEINTS))                newVal &= ~IDEINTS; // clear the interrupt?            else                (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS;            if ((oldVal & IDEDMAE) && (newVal & IDEDMAE))                newVal &= ~IDEDMAE;            else                (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;            bmi_regs.chan[channel].bmis = newVal;            break;            // Bus master IDE descriptor table pointer register          case BMIDTP0:          case BMIDTP1:            {                if (pkt->getSize() != sizeof(uint32_t))                    panic("Invalid BMIDTP write size: %x\n", pkt->getSize());                bmi_regs.chan[channel].bmidtp = htole(pkt->get<uint32_t>() & ~0x3);            }            break;          default:            if (pkt->getSize() != sizeof(uint8_t) &&                pkt->getSize() != sizeof(uint16_t) &&                pkt->getSize() != sizeof(uint32_t))                panic("IDE controller write of invalid write size: %x\n",                      pkt->getSize());            // do a default copy of data into the registers            memcpy(&bmi_regs.data[offset], pkt->getPtr<uint8_t>(), pkt->getSize());        }        break;      case COMMAND_BLOCK:        if (offset == IDE_SELECT_OFFSET) {            uint8_t *devBit = &dev[channel];            *devBit = (letoh(pkt->get<uint8_t>()) & IDE_SELECT_DEV_BIT) ? 1 : 0;        }        // fall-through ok!      case CONTROL_BLOCK:        disk = getDisk(channel);        if (disks[disk] == NULL)            break;        switch (offset) {          case DATA_OFFSET:            switch (pkt->getSize()) {              case sizeof(uint16_t):                disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());                break;              case sizeof(uint32_t):                disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());                disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>() +                        sizeof(uint16_t));                break;              default:                panic("IDE write of data reg invalid size: %#x\n", pkt->getSize());            }            break;          default:            if (pkt->getSize() == sizeof(uint8_t)) {                disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());            } else                panic("IDE write of command reg of invalid size: %#x\n", pkt->getSize());        }        break;      default:        panic("IDE controller write of unknown register block type!\n");    }    if (pkt->getSize() == 1)    DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",            offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>());    else if (pkt->getSize() == 2)    DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",            offset, pkt->getSize(), pkt->get<uint16_t>());    else    DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",            offset, pkt->getSize(), pkt->get<uint32_t>());    pkt->makeAtomicResponse();    return pioDelay;}////// Serialization////voidIdeController::serialize(std::ostream &os){    // Serialize the PciDev base class    PciDev::serialize(os);    // Serialize register addresses and sizes    SERIALIZE_SCALAR(pri_cmd_addr);    SERIALIZE_SCALAR(pri_cmd_size);    SERIALIZE_SCALAR(pri_ctrl_addr);    SERIALIZE_SCALAR(pri_ctrl_size);    SERIALIZE_SCALAR(sec_cmd_addr);    SERIALIZE_SCALAR(sec_cmd_size);    SERIALIZE_SCALAR(sec_ctrl_addr);    SERIALIZE_SCALAR(sec_ctrl_size);    SERIALIZE_SCALAR(bmi_addr);    SERIALIZE_SCALAR(bmi_size);    // Serialize registers    SERIALIZE_ARRAY(bmi_regs.data,                    sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));    SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));    SERIALIZE_ARRAY(config_regs.data,                    sizeof(config_regs.data) / sizeof(config_regs.data[0]));    // Serialize internal state    SERIALIZE_SCALAR(io_enabled);    SERIALIZE_SCALAR(bm_enabled);    SERIALIZE_ARRAY(cmd_in_progress,                    sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));}voidIdeController::unserialize(Checkpoint *cp, const std::string &section){    // Unserialize the PciDev base class    PciDev::unserialize(cp, section);    // Unserialize register addresses and sizes    UNSERIALIZE_SCALAR(pri_cmd_addr);    UNSERIALIZE_SCALAR(pri_cmd_size);    UNSERIALIZE_SCALAR(pri_ctrl_addr);    UNSERIALIZE_SCALAR(pri_ctrl_size);    UNSERIALIZE_SCALAR(sec_cmd_addr);    UNSERIALIZE_SCALAR(sec_cmd_size);    UNSERIALIZE_SCALAR(sec_ctrl_addr);    UNSERIALIZE_SCALAR(sec_ctrl_size);    UNSERIALIZE_SCALAR(bmi_addr);    UNSERIALIZE_SCALAR(bmi_size);    // Unserialize registers    UNSERIALIZE_ARRAY(bmi_regs.data,                      sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));    UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));    UNSERIALIZE_ARRAY(config_regs.data,                      sizeof(config_regs.data) / sizeof(config_regs.data[0]));    // Unserialize internal state    UNSERIALIZE_SCALAR(io_enabled);    UNSERIALIZE_SCALAR(bm_enabled);    UNSERIALIZE_ARRAY(cmd_in_progress,                      sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));}IdeController *IdeControllerParams::create(){    return new IdeController(this);}

⌨️ 快捷键说明

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