diff options
Diffstat (limited to 'dev')
-rw-r--r-- | dev/ide_disk.cc | 168 | ||||
-rw-r--r-- | dev/ide_disk.hh | 41 | ||||
-rw-r--r-- | dev/tsunami_pchip.cc | 40 | ||||
-rw-r--r-- | dev/tsunami_pchip.hh | 3 |
4 files changed, 165 insertions, 87 deletions
diff --git a/dev/ide_disk.cc b/dev/ide_disk.cc index 0d825b723..df365bab9 100644 --- a/dev/ide_disk.cc +++ b/dev/ide_disk.cc @@ -61,25 +61,12 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, dmaWriteWaitEvent(this), dmaPrdReadEvent(this), dmaReadEvent(this), dmaWriteEvent(this) { + // Reset the device state + reset(id); + // calculate disk delay in microseconds diskDelay = (delay * ticksPerSecond / 100000); - // 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)); - - dmaInterfaceBytes = 0; - curPrdAddr = 0; - curSector = 0; - curCommand = 0; - cmdBytesLeft = 0; - drqBytesLeft = 0; - dmaRead = false; - intrPending = false; - // fill out the drive ID structure memset(&driveID, 0, sizeof(struct hd_driveid)); @@ -132,6 +119,32 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, driveID.dma_ultra = 0x10; // Statically set hardware config word driveID.hw_config = 0x4001; +} + +IdeDisk::~IdeDisk() +{ + // destroy the data buffer + delete [] dataBuffer; +} + +void +IdeDisk::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)); + + dmaInterfaceBytes = 0; + curPrdAddr = 0; + curSector = 0; + cmdBytes = 0; + cmdBytesLeft = 0; + drqBytesLeft = 0; + dmaRead = false; + intrPending = false; // set the device state to idle dmaState = Dma_Idle; @@ -147,13 +160,7 @@ IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, } // set the device ready bit - cmdReg.status |= STATUS_DRDY_BIT; -} - -IdeDisk::~IdeDisk() -{ - // destroy the data buffer - delete [] dataBuffer; + status = STATUS_DRDY_BIT; } //// @@ -216,6 +223,7 @@ IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data) // determine if an action needs to be taken on the state machine if (offset == STATUS_OFFSET) { action = ACT_STAT_READ; + *data = status; // status is in a shadow, explicity copy } else if (offset == DATA_OFFSET) { if (byte) action = ACT_DATA_READ_BYTE; @@ -230,7 +238,7 @@ IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data) if (!byte) panic("Invalid 16-bit read from control block\n"); - *data = ((uint8_t *)&cmdReg)[STATUS_OFFSET]; + *data = status; } if (action != ACT_NONE) @@ -262,6 +270,8 @@ IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data) action = ACT_DATA_WRITE_BYTE; else action = ACT_DATA_WRITE_SHORT; + } else if (offset == SELECT_OFFSET) { + action = ACT_SELECT_WRITE; } } else { @@ -271,8 +281,13 @@ IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data) if (!byte) panic("Invalid 16-bit write to control block\n"); - if (*data & CONTROL_RST_BIT) - panic("Software reset not supported!\n"); + 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; } @@ -315,7 +330,13 @@ IdeDisk::dmaPrdReadDone() physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)), sizeof(PrdEntry_t)); - curPrdAddr += sizeof(PrdEntry_t); + 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); + + // make sure the new curPrdAddr is properly translated from PCI to system + curPrdAddr = pciToDma(curPrdAddr + sizeof(PrdEntry_t)); if (dmaRead) doDmaRead(); @@ -598,7 +619,8 @@ IdeDisk::startDma(const uint32_t &prdTableBase) if (devState != Transfer_Data_Dma) panic("Inconsistent device state for DMA start!\n"); - curPrdAddr = pciToDma((Addr)prdTableBase); + // PRD base address is given by bits 31:2 + curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); dmaState = Dma_Transfer; @@ -625,9 +647,6 @@ IdeDisk::startCommand() uint32_t size = 0; dmaRead = false; - // copy the command to the shadow - curCommand = cmdReg.command; - // Decode commands switch (cmdReg.command) { // Supported non-data commands @@ -656,7 +675,7 @@ IdeDisk::startCommand() // Supported PIO data-in commands case WIN_IDENTIFY: - cmdBytesLeft = sizeof(struct hd_driveid); + cmdBytes = cmdBytesLeft = sizeof(struct hd_driveid); devState = Prepare_Data_In; action = ACT_DATA_READY; break; @@ -667,9 +686,9 @@ IdeDisk::startCommand() panic("Attempt to perform CHS access, only supports LBA\n"); if (cmdReg.sec_count == 0) - cmdBytesLeft = (256 * SectorSize); + cmdBytes = cmdBytesLeft = (256 * SectorSize); else - cmdBytesLeft = (cmdReg.sec_count * SectorSize); + cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); curSector = getLBABase(); @@ -685,9 +704,9 @@ IdeDisk::startCommand() panic("Attempt to perform CHS access, only supports LBA\n"); if (cmdReg.sec_count == 0) - cmdBytesLeft = (256 * SectorSize); + cmdBytes = cmdBytesLeft = (256 * SectorSize); else - cmdBytesLeft = (cmdReg.sec_count * SectorSize); + cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); curSector = getLBABase(); @@ -703,9 +722,9 @@ IdeDisk::startCommand() panic("Attempt to perform CHS access, only supports LBA\n"); if (cmdReg.sec_count == 0) - cmdBytesLeft = (256 * SectorSize); + cmdBytes = cmdBytesLeft = (256 * SectorSize); else - cmdBytesLeft = (cmdReg.sec_count * SectorSize); + cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); curSector = getLBABase(); @@ -719,9 +738,11 @@ IdeDisk::startCommand() if (action != ACT_NONE) { // set the BSY bit - cmdReg.status |= STATUS_BSY_BIT; + status |= STATUS_BSY_BIT; // clear the DRQ bit - cmdReg.status &= ~STATUS_DRQ_BIT; + status &= ~STATUS_DRQ_BIT; + // clear the DF bit + status &= ~STATUS_DF_BIT; updateState(action); } @@ -765,16 +786,30 @@ void IdeDisk::updateState(DevAction_t action) { switch (devState) { + case Device_Srst: + if (action == ACT_SRST_SET) { + // set the BSY bit + status |= STATUS_BSY_BIT; + } else if (action == ACT_SRST_CLEAR) { + // clear the BSY bit + status &= ~STATUS_BSY_BIT; + + // reset the device state + reset(devID); + } + break; + case Device_Idle_S: - if (!isDEVSelect()) + if (action == ACT_SELECT_WRITE && !isDEVSelect()) { devState = Device_Idle_NS; - else if (action == ACT_CMD_WRITE) + } else if (action == ACT_CMD_WRITE) { startCommand(); + } break; case Device_Idle_SI: - if (!isDEVSelect()) { + if (action == ACT_SELECT_WRITE && !isDEVSelect()) { devState = Device_Idle_NS; intrClear(); } else if (action == ACT_STAT_READ || isIENSet()) { @@ -788,7 +823,7 @@ IdeDisk::updateState(DevAction_t action) break; case Device_Idle_NS: - if (isDEVSelect()) { + if (action == ACT_SELECT_WRITE && isDEVSelect()) { if (!isIENSet() && intrPending) { devState = Device_Idle_SI; intrPost(); @@ -826,12 +861,12 @@ IdeDisk::updateState(DevAction_t action) } } else if (action == ACT_DATA_READY) { // clear the BSY bit - cmdReg.status &= ~STATUS_BSY_BIT; + status &= ~STATUS_BSY_BIT; // set the DRQ bit - cmdReg.status |= STATUS_DRQ_BIT; + status |= STATUS_DRQ_BIT; // copy the data into the data buffer - if (curCommand == WIN_IDENTIFY) { + if (cmdReg.command == WIN_IDENTIFY) { // Reset the drqBytes for this block drqBytesLeft = sizeof(struct hd_driveid); @@ -887,9 +922,9 @@ IdeDisk::updateState(DevAction_t action) } else { devState = Prepare_Data_In; // set the BSY_BIT - cmdReg.status |= STATUS_BSY_BIT; + status |= STATUS_BSY_BIT; // clear the DRQ_BIT - cmdReg.status &= ~STATUS_DRQ_BIT; + status &= ~STATUS_DRQ_BIT; /** @todo change this to a scheduled event to simulate disk delay */ @@ -910,20 +945,23 @@ IdeDisk::updateState(DevAction_t action) } else { devState = Device_Idle_S; } - } else if (cmdBytesLeft != 0) { + } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { // clear the BSY bit - cmdReg.status &= ~STATUS_BSY_BIT; + status &= ~STATUS_BSY_BIT; // set the DRQ bit - cmdReg.status |= STATUS_DRQ_BIT; + status |= STATUS_DRQ_BIT; // clear the data buffer to get it ready for writes memset(dataBuffer, 0, MAX_DMA_SIZE); - if (!isIENSet()) { + // reset the drqBytes for this block + drqBytesLeft = SectorSize; + + if (cmdBytesLeft == cmdBytes || isIENSet()) { + devState = Transfer_Data_Out; + } else { devState = Data_Ready_INTRQ_Out; intrPost(); - } else { - devState = Transfer_Data_Out; } } break; @@ -956,9 +994,11 @@ IdeDisk::updateState(DevAction_t action) writeDisk(curSector++, dataBuffer); // set the BSY bit - cmdReg.status |= STATUS_BSY_BIT; + status |= STATUS_BSY_BIT; + // set the seek bit + status |= STATUS_SEEK_BIT; // clear the DRQ bit - cmdReg.status &= ~STATUS_DRQ_BIT; + status &= ~STATUS_DRQ_BIT; devState = Prepare_Data_Out; @@ -982,9 +1022,9 @@ IdeDisk::updateState(DevAction_t action) } } else if (action == ACT_DMA_READY) { // clear the BSY bit - cmdReg.status &= ~STATUS_BSY_BIT; + status &= ~STATUS_BSY_BIT; // set the DRQ bit - cmdReg.status |= STATUS_DRQ_BIT; + status |= STATUS_DRQ_BIT; devState = Transfer_Data_Dma; @@ -1001,7 +1041,7 @@ IdeDisk::updateState(DevAction_t action) // clear the BSY bit setComplete(); // set the seek bit - cmdReg.status |= 0x10; + status |= STATUS_SEEK_BIT; // clear the controller state for DMA transfer ctrl->setDmaComplete(this); @@ -1058,7 +1098,7 @@ IdeDisk::serialize(ostream &os) SERIALIZE_SCALAR(cmdReg.cyl_low); SERIALIZE_SCALAR(cmdReg.cyl_high); SERIALIZE_SCALAR(cmdReg.drive); - SERIALIZE_SCALAR(cmdReg.status); + SERIALIZE_SCALAR(status); SERIALIZE_SCALAR(nIENBit); SERIALIZE_SCALAR(devID); @@ -1070,9 +1110,9 @@ IdeDisk::serialize(ostream &os) // Serialize current transfer related information SERIALIZE_SCALAR(cmdBytesLeft); + SERIALIZE_SCALAR(cmdBytes); SERIALIZE_SCALAR(drqBytesLeft); SERIALIZE_SCALAR(curSector); - SERIALIZE_SCALAR(curCommand); SERIALIZE_SCALAR(dmaRead); SERIALIZE_SCALAR(dmaInterfaceBytes); SERIALIZE_SCALAR(intrPending); @@ -1110,7 +1150,7 @@ IdeDisk::unserialize(Checkpoint *cp, const string §ion) UNSERIALIZE_SCALAR(cmdReg.cyl_low); UNSERIALIZE_SCALAR(cmdReg.cyl_high); UNSERIALIZE_SCALAR(cmdReg.drive); - UNSERIALIZE_SCALAR(cmdReg.status); + UNSERIALIZE_SCALAR(status); UNSERIALIZE_SCALAR(nIENBit); UNSERIALIZE_SCALAR(devID); @@ -1121,10 +1161,10 @@ IdeDisk::unserialize(Checkpoint *cp, const string §ion) UNSERIALIZE_SCALAR(curPrdAddr); // Unserialize current transfer related information + UNSERIALIZE_SCALAR(cmdBytes); UNSERIALIZE_SCALAR(cmdBytesLeft); UNSERIALIZE_SCALAR(drqBytesLeft); UNSERIALIZE_SCALAR(curSector); - UNSERIALIZE_SCALAR(curCommand); UNSERIALIZE_SCALAR(dmaRead); UNSERIALIZE_SCALAR(dmaInterfaceBytes); UNSERIALIZE_SCALAR(intrPending); diff --git a/dev/ide_disk.hh b/dev/ide_disk.hh index e580038b0..409aaef9a 100644 --- a/dev/ide_disk.hh +++ b/dev/ide_disk.hh @@ -40,8 +40,8 @@ #define DMA_BACKOFF_PERIOD 200 -#define MAX_DMA_SIZE (131072) // 256 * SectorSize (512) -#define MAX_MULTSECT (128) +#define MAX_DMA_SIZE (65536) // 64K +#define MAX_MULTSECT (128) #define PRD_BASE_MASK 0xfffffffe #define PRD_COUNT_MASK 0xfffe @@ -62,7 +62,7 @@ class PrdTableEntry { return (entry.baseAddr & PRD_BASE_MASK); } - uint16_t getByteCount() + uint32_t getByteCount() { return ((entry.byteCount == 0) ? MAX_DMA_SIZE : (entry.byteCount & PRD_COUNT_MASK)); @@ -94,6 +94,8 @@ class PrdTableEntry { #define STATUS_BSY_BIT 0x80 #define STATUS_DRDY_BIT 0x40 #define STATUS_DRQ_BIT 0x08 +#define STATUS_SEEK_BIT 0x10 +#define STATUS_DF_BIT 0x20 #define DRIVE_LBA_BIT 0x40 #define DEV0 (0) @@ -114,10 +116,7 @@ typedef struct CommandReg { uint8_t drive; uint8_t head; }; - union { - uint8_t status; - uint8_t command; - }; + uint8_t command; } CommandReg_t; typedef enum Events { @@ -135,6 +134,7 @@ typedef enum DevAction { ACT_CMD_WRITE, ACT_CMD_COMPLETE, ACT_CMD_ERROR, + ACT_SELECT_WRITE, ACT_STAT_READ, ACT_DATA_READY, ACT_DATA_READ_BYTE, @@ -142,7 +142,9 @@ typedef enum DevAction { ACT_DATA_WRITE_BYTE, ACT_DATA_WRITE_SHORT, ACT_DMA_READY, - ACT_DMA_DONE + ACT_DMA_DONE, + ACT_SRST_SET, + ACT_SRST_CLEAR } DevAction_t; typedef enum DevState { @@ -151,6 +153,9 @@ typedef enum DevState { Device_Idle_SI, Device_Idle_NS, + // Software reset + Device_Srst, + // Non-data commands Command_Execution, @@ -202,6 +207,8 @@ class IdeDisk : public SimObject struct hd_driveid driveID; /** Data buffer for transfers */ uint8_t *dataBuffer; + /** Number of bytes in command data transfer */ + uint32_t cmdBytes; /** Number of bytes left in command data transfer */ uint32_t cmdBytesLeft; /** Number of bytes left in DRQ block */ @@ -210,8 +217,8 @@ class IdeDisk : public SimObject uint32_t curSector; /** Command block registers */ CommandReg_t cmdReg; - /** Shadow of the current command code */ - uint8_t curCommand; + /** Status register */ + uint8_t status; /** Interrupt enable bit */ bool nIENBit; /** Device state */ @@ -249,6 +256,11 @@ class IdeDisk : public SimObject ~IdeDisk(); /** + * Reset the device state + */ + void reset(int id); + + /** * Set the controller for this device * @param c The IDE controller */ @@ -306,17 +318,18 @@ class IdeDisk : public SimObject void updateState(DevAction_t action); // Utility functions - bool isBSYSet() { return (cmdReg.status & STATUS_BSY_BIT); } + bool isBSYSet() { return (status & STATUS_BSY_BIT); } bool isIENSet() { return nIENBit; } bool isDEVSelect() { return ((cmdReg.drive & SELECT_DEV_BIT) == devID); } void setComplete() { // clear out the status byte - cmdReg.status = 0; - + status = 0; // set the DRDY bit - cmdReg.status |= STATUS_DRDY_BIT; + status |= STATUS_DRDY_BIT; + // set the SEEK bit + status |= STATUS_SEEK_BIT; } uint32_t getLBABase() diff --git a/dev/tsunami_pchip.cc b/dev/tsunami_pchip.cc index 510cface8..e65b235bd 100644 --- a/dev/tsunami_pchip.cc +++ b/dev/tsunami_pchip.cc @@ -62,6 +62,9 @@ TsunamiPChip::TsunamiPChip(const string &name, Tsunami *t, Addr a, tba[i] = 0; } + // initialize pchip control register + pctl = (ULL(0x1) << 20) | (ULL(0x1) << 32) | (ULL(0x2) << 36); + //Set back pointer in tsunami tsunami->pchip = this; } @@ -115,8 +118,7 @@ TsunamiPChip::read(MemReqPtr &req, uint8_t *data) *(uint64_t*)data = tba[3]; return No_Fault; case TSDEV_PC_PCTL: - // might want to change the clock?? - *(uint64_t*)data = 0x00; // try this + *(uint64_t*)data = pctl; return No_Fault; case TSDEV_PC_PLAT: panic("PC_PLAT not implemented\n"); @@ -205,7 +207,7 @@ TsunamiPChip::write(MemReqPtr &req, const uint8_t *data) tba[3] = *(uint64_t*)data; return No_Fault; case TSDEV_PC_PCTL: - // might want to change the clock?? + pctl = *(uint64_t*)data; return No_Fault; case TSDEV_PC_PLAT: panic("PC_PLAT not implemented\n"); @@ -260,12 +262,29 @@ TsunamiPChip::translatePciToDma(Addr busAddr) Addr pteAddr; Addr dmaAddr; +#if 0 + DPRINTF(IdeDisk, "Translation for bus address: %#x\n", busAddr); for (int i = 0; i < 4; i++) { + DPRINTF(IdeDisk, "(%d) base:%#x mask:%#x\n", + i, wsba[i], wsm[i]); + windowBase = wsba[i]; - windowMask = ~wsm[i] & (0x7ff << 20); + windowMask = ~wsm[i] & (ULL(0xfff) << 20); if ((busAddr & windowMask) == (windowBase & windowMask)) { + DPRINTF(IdeDisk, "Would have matched %d (wb:%#x wm:%#x --> ba&wm:%#x wb&wm:%#x)\n", + i, windowBase, windowMask, (busAddr & windowMask), + (windowBase & windowMask)); + } + } +#endif + for (int i = 0; i < 4; i++) { + + windowBase = wsba[i]; + windowMask = ~wsm[i] & (ULL(0xfff) << 20); + + if ((busAddr & windowMask) == (windowBase & windowMask)) { if (wsba[i] & 0x1) { // see if enabled if (wsba[i] & 0x2) { // see if SG bit is set @@ -279,8 +298,8 @@ TsunamiPChip::translatePciToDma(Addr busAddr) to create an address for the SG page */ - tbaMask = ~(((wsm[i] & (0x7ff << 20)) >> 10) | 0x3ff); - baMask = (wsm[i] & (0x7ff << 20)) | (0x7f << 13); + tbaMask = ~(((wsm[i] & (ULL(0xfff) << 20)) >> 10) | ULL(0x3ff)); + baMask = (wsm[i] & (ULL(0xfff) << 20)) | (ULL(0x7f) << 13); pteAddr = (tba[i] & tbaMask) | ((busAddr & baMask) >> 10); memcpy((void *)&pteEntry, @@ -288,10 +307,10 @@ TsunamiPChip::translatePciToDma(Addr busAddr) physmem->dma_addr(pteAddr, sizeof(uint64_t)), sizeof(uint64_t)); - dmaAddr = ((pteEntry & ~0x1) << 12) | (busAddr & 0x1fff); + dmaAddr = ((pteEntry & ~ULL(0x1)) << 12) | (busAddr & ULL(0x1fff)); } else { - baMask = (wsm[i] & (0x7ff << 20)) | 0xfffff; + baMask = (wsm[i] & (ULL(0xfff) << 20)) | ULL(0xfffff); tbaMask = ~baMask; dmaAddr = (tba[i] & tbaMask) | (busAddr & baMask); } @@ -301,12 +320,14 @@ TsunamiPChip::translatePciToDma(Addr busAddr) } } - return 0; + // if no match was found, then return the original address + return busAddr; } void TsunamiPChip::serialize(std::ostream &os) { + SERIALIZE_SCALAR(pctl); SERIALIZE_ARRAY(wsba, 4); SERIALIZE_ARRAY(wsm, 4); SERIALIZE_ARRAY(tba, 4); @@ -315,6 +336,7 @@ TsunamiPChip::serialize(std::ostream &os) void TsunamiPChip::unserialize(Checkpoint *cp, const std::string §ion) { + UNSERIALIZE_SCALAR(pctl); UNSERIALIZE_ARRAY(wsba, 4); UNSERIALIZE_ARRAY(wsm, 4); UNSERIALIZE_ARRAY(tba, 4); diff --git a/dev/tsunami_pchip.hh b/dev/tsunami_pchip.hh index 130e71db1..f3c250d71 100644 --- a/dev/tsunami_pchip.hh +++ b/dev/tsunami_pchip.hh @@ -56,6 +56,9 @@ class TsunamiPChip : public FunctionalMemory */ Tsunami *tsunami; + /** Pchip control register */ + uint64_t pctl; + /** Window Base addresses */ uint64_t wsba[4]; |