1/* 2 * Copyright (c) 2013 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2004-2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Andrew Schultz 41 * Ali Saidi 42 */ 43 44/** @file 45 * Device model implementation for an IDE disk 46 */ 47 48#include "dev/storage/ide_disk.hh" 49 50#include <cerrno> 51#include <cstring> 52#include <deque> 53#include <string> 54 55#include "arch/isa_traits.hh" 56#include "base/chunk_generator.hh" 57#include "base/cprintf.hh" // csprintf 58#include "base/trace.hh" 59#include "config/the_isa.hh" 60#include "debug/IdeDisk.hh" 61#include "dev/storage/disk_image.hh" 62#include "dev/storage/ide_ctrl.hh" 63#include "sim/core.hh" 64#include "sim/sim_object.hh" 65 66using namespace std; 67using namespace TheISA; 68 69IdeDisk::IdeDisk(const Params *p) 70 : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay), 71 dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this), 72 dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this), 73 dmaReadEvent(this), dmaWriteEvent(this) 74{ 75 // Reset the device state 76 reset(p->driveID); 77 78 // fill out the drive ID structure 79 memset(&driveID, 0, sizeof(struct ataparams)); 80 81 // Calculate LBA and C/H/S values 82 uint16_t cylinders; 83 uint8_t heads; 84 uint8_t sectors; 85 86 uint32_t lba_size = image->size(); 87 if (lba_size >= 16383*16*63) { 88 cylinders = 16383; 89 heads = 16; 90 sectors = 63; 91 } else { 92 if (lba_size >= 63) 93 sectors = 63; 94 else if (lba_size == 0) 95 panic("Bad IDE image size: 0\n"); 96 else 97 sectors = lba_size; 98 99 if ((lba_size / sectors) >= 16) 100 heads = 16; 101 else 102 heads = (lba_size / sectors); 103 104 cylinders = lba_size / (heads * sectors); 105 } 106 107 // Setup the model name 108 strncpy((char *)driveID.atap_model, "5MI EDD si k", 109 sizeof(driveID.atap_model)); 110 // Set the maximum multisector transfer size 111 driveID.atap_multi = MAX_MULTSECT; 112 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled 113 driveID.atap_capabilities1 = 0x7; 114 // UDMA support, EIDE support 115 driveID.atap_extensions = 0x6; 116 // Setup default C/H/S settings 117 driveID.atap_cylinders = cylinders; 118 driveID.atap_sectors = sectors; 119 driveID.atap_heads = heads; 120 // Setup the current multisector transfer size 121 driveID.atap_curmulti = MAX_MULTSECT; 122 driveID.atap_curmulti_valid = 0x1; 123 // Number of sectors on disk 124 driveID.atap_capacity = lba_size; 125 // Multiword DMA mode 2 and below supported 126 driveID.atap_dmamode_supp = 0x4; 127 // Set PIO mode 4 and 3 supported 128 driveID.atap_piomode_supp = 0x3; 129 // Set DMA mode 4 and below supported 130 driveID.atap_udmamode_supp = 0x1f; 131 // Statically set hardware config word 132 driveID.atap_hwreset_res = 0x4001; 133 134 //arbitrary for now... 135 driveID.atap_ata_major = WDC_VER_ATA7; 136} 137 138IdeDisk::~IdeDisk() 139{ 140 // destroy the data buffer 141 delete [] dataBuffer; 142} 143 144void 145IdeDisk::reset(int id) 146{ 147 // initialize the data buffer and shadow registers 148 dataBuffer = new uint8_t[MAX_DMA_SIZE]; 149 150 memset(dataBuffer, 0, MAX_DMA_SIZE); 151 memset(&cmdReg, 0, sizeof(CommandReg_t)); 152 memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); 153 154 curPrdAddr = 0; 155 curSector = 0; 156 cmdBytes = 0; 157 cmdBytesLeft = 0; 158 drqBytesLeft = 0; 159 dmaRead = false; 160 intrPending = false; 161 dmaAborted = false; 162 163 // set the device state to idle 164 dmaState = Dma_Idle; 165 166 if (id == DEV0) { 167 devState = Device_Idle_S; 168 devID = DEV0; 169 } else if (id == DEV1) { 170 devState = Device_Idle_NS; 171 devID = DEV1; 172 } else { 173 panic("Invalid device ID: %#x\n", id); 174 } 175 176 // set the device ready bit 177 status = STATUS_DRDY_BIT; 178 179 /* The error register must be set to 0x1 on start-up to 180 indicate that no diagnostic error was detected */ 181 cmdReg.error = 0x1; 182} 183 184//// 185// Utility functions 186//// 187 188bool 189IdeDisk::isDEVSelect() 190{ 191 return ctrl->isDiskSelected(this); 192} 193 194Addr 195IdeDisk::pciToDma(Addr pciAddr) 196{ 197 if (ctrl) 198 return ctrl->pciToDma(pciAddr); 199 else 200 panic("Access to unset controller!\n"); 201} 202 203//// 204// Device registers read/write 205//// 206 207void 208IdeDisk::readCommand(const Addr offset, int size, uint8_t *data) 209{ 210 if (offset == DATA_OFFSET) { 211 if (size == sizeof(uint16_t)) { 212 *(uint16_t *)data = cmdReg.data; 213 } else if (size == sizeof(uint32_t)) { 214 *(uint16_t *)data = cmdReg.data; 215 updateState(ACT_DATA_READ_SHORT); 216 *((uint16_t *)data + 1) = cmdReg.data; 217 } else { 218 panic("Data read of unsupported size %d.\n", size); 219 } 220 updateState(ACT_DATA_READ_SHORT); 221 return; 222 } 223 assert(size == sizeof(uint8_t)); 224 switch (offset) { 225 case ERROR_OFFSET: 226 *data = cmdReg.error; 227 break; 228 case NSECTOR_OFFSET: 229 *data = cmdReg.sec_count; 230 break; 231 case SECTOR_OFFSET: 232 *data = cmdReg.sec_num; 233 break; 234 case LCYL_OFFSET: 235 *data = cmdReg.cyl_low; 236 break; 237 case HCYL_OFFSET: 238 *data = cmdReg.cyl_high; 239 break; 240 case DRIVE_OFFSET: 241 *data = cmdReg.drive; 242 break; 243 case STATUS_OFFSET: 244 *data = status; 245 updateState(ACT_STAT_READ); 246 break; 247 default: 248 panic("Invalid IDE command register offset: %#x\n", offset); 249 } 250 DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data); 251} 252 253void 254IdeDisk::readControl(const Addr offset, int size, uint8_t *data) 255{ 256 assert(size == sizeof(uint8_t)); 257 *data = status; 258 if (offset != ALTSTAT_OFFSET) 259 panic("Invalid IDE control register offset: %#x\n", offset); 260 DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data); 261} 262 263void 264IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data) 265{ 266 if (offset == DATA_OFFSET) { 267 if (size == sizeof(uint16_t)) { 268 cmdReg.data = *(const uint16_t *)data; 269 } else if (size == sizeof(uint32_t)) { 270 cmdReg.data = *(const uint16_t *)data; 271 updateState(ACT_DATA_WRITE_SHORT); 272 cmdReg.data = *((const uint16_t *)data + 1); 273 } else { 274 panic("Data write of unsupported size %d.\n", size); 275 } 276 updateState(ACT_DATA_WRITE_SHORT); 277 return; 278 } 279 280 assert(size == sizeof(uint8_t)); 281 switch (offset) { 282 case FEATURES_OFFSET: 283 break; 284 case NSECTOR_OFFSET: 285 cmdReg.sec_count = *data; 286 break; 287 case SECTOR_OFFSET: 288 cmdReg.sec_num = *data; 289 break; 290 case LCYL_OFFSET: 291 cmdReg.cyl_low = *data; 292 break; 293 case HCYL_OFFSET: 294 cmdReg.cyl_high = *data; 295 break; 296 case DRIVE_OFFSET: 297 cmdReg.drive = *data; 298 updateState(ACT_SELECT_WRITE); 299 break; 300 case COMMAND_OFFSET: 301 cmdReg.command = *data; 302 updateState(ACT_CMD_WRITE); 303 break; 304 default: 305 panic("Invalid IDE command register offset: %#x\n", offset); 306 } 307 DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset, 308 (uint32_t)*data); 309} 310 311void 312IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data) 313{ 314 if (offset != CONTROL_OFFSET) 315 panic("Invalid IDE control register offset: %#x\n", offset); 316 317 if (*data & CONTROL_RST_BIT) { 318 // force the device into the reset state 319 devState = Device_Srst; 320 updateState(ACT_SRST_SET); 321 } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) { 322 updateState(ACT_SRST_CLEAR); 323 } 324 325 nIENBit = *data & CONTROL_IEN_BIT; 326 327 DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset, 328 (uint32_t)*data); 329} 330 331//// 332// Perform DMA transactions 333//// 334 335void 336IdeDisk::doDmaTransfer() 337{ 338 if (dmaAborted) { 339 DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n"); 340 updateState(ACT_CMD_ERROR); 341 return; 342 } 343 344 if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) 345 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", 346 dmaState, devState); 347 348 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) { 349 schedule(dmaTransferEvent, curTick() + DMA_BACKOFF_PERIOD); 350 return; 351 } else 352 ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent, 353 (uint8_t*)&curPrd.entry); 354} 355 356void 357IdeDisk::dmaPrdReadDone() 358{ 359 if (dmaAborted) { 360 DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n"); 361 updateState(ACT_CMD_ERROR); 362 return; 363 } 364 365 DPRINTF(IdeDisk, 366 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n", 367 curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()), 368 curPrd.getByteCount(), (cmdBytesLeft/SectorSize), 369 curPrd.getEOT(), curSector); 370 371 // the prd pointer has already been translated, so just do an increment 372 curPrdAddr = curPrdAddr + sizeof(PrdEntry_t); 373 374 if (dmaRead) 375 doDmaDataRead(); 376 else 377 doDmaDataWrite(); 378} 379 380void 381IdeDisk::doDmaDataRead() 382{ 383 /** @todo we need to figure out what the delay actually will be */ 384 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 385 386 DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n", 387 diskDelay, totalDiskDelay); 388 389 schedule(dmaReadWaitEvent, curTick() + totalDiskDelay); 390} 391 392void 393IdeDisk::regStats() 394{ 395 SimObject::regStats(); 396 397 using namespace Stats; 398 dmaReadFullPages 399 .name(name() + ".dma_read_full_pages") 400 .desc("Number of full page size DMA reads (not PRD).") 401 ; 402 dmaReadBytes 403 .name(name() + ".dma_read_bytes") 404 .desc("Number of bytes transfered via DMA reads (not PRD).") 405 ; 406 dmaReadTxs 407 .name(name() + ".dma_read_txs") 408 .desc("Number of DMA read transactions (not PRD).") 409 ; 410 411 dmaWriteFullPages 412 .name(name() + ".dma_write_full_pages") 413 .desc("Number of full page size DMA writes.") 414 ; 415 dmaWriteBytes 416 .name(name() + ".dma_write_bytes") 417 .desc("Number of bytes transfered via DMA writes.") 418 ; 419 dmaWriteTxs 420 .name(name() + ".dma_write_txs") 421 .desc("Number of DMA write transactions.") 422 ; 423} 424 425void 426IdeDisk::doDmaRead() 427{ 428 if (dmaAborted) { 429 DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n"); 430 if (dmaReadCG) 431 delete dmaReadCG; 432 dmaReadCG = NULL; 433 updateState(ACT_CMD_ERROR); 434 return; 435 } 436 437 if (!dmaReadCG) { 438 // clear out the data buffer 439 memset(dataBuffer, 0, MAX_DMA_SIZE); 440 dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(), 441 curPrd.getByteCount(), TheISA::PageBytes); 442 443 } 444 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) { 445 schedule(dmaReadWaitEvent, curTick() + DMA_BACKOFF_PERIOD); 446 return; 447 } else if (!dmaReadCG->done()) { 448 assert(dmaReadCG->complete() < MAX_DMA_SIZE); 449 ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(), 450 &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete()); 451 dmaReadBytes += dmaReadCG->size(); 452 dmaReadTxs++; 453 if (dmaReadCG->size() == TheISA::PageBytes) 454 dmaReadFullPages++; 455 dmaReadCG->next(); 456 } else { 457 assert(dmaReadCG->done()); 458 delete dmaReadCG; 459 dmaReadCG = NULL; 460 dmaReadDone(); 461 } 462} 463 464void 465IdeDisk::dmaReadDone() 466{ 467 uint32_t bytesWritten = 0; 468 469 // write the data to the disk image 470 for (bytesWritten = 0; bytesWritten < curPrd.getByteCount(); 471 bytesWritten += SectorSize) { 472 473 cmdBytesLeft -= SectorSize; 474 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 475 } 476 477 // check for the EOT 478 if (curPrd.getEOT()) { 479 assert(cmdBytesLeft == 0); 480 dmaState = Dma_Idle; 481 updateState(ACT_DMA_DONE); 482 } else { 483 doDmaTransfer(); 484 } 485} 486 487void 488IdeDisk::doDmaDataWrite() 489{ 490 /** @todo we need to figure out what the delay actually will be */ 491 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 492 uint32_t bytesRead = 0; 493 494 DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", 495 diskDelay, totalDiskDelay); 496 497 memset(dataBuffer, 0, MAX_DMA_SIZE); 498 assert(cmdBytesLeft <= MAX_DMA_SIZE); 499 while (bytesRead < curPrd.getByteCount()) { 500 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); 501 bytesRead += SectorSize; 502 cmdBytesLeft -= SectorSize; 503 } 504 DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n", 505 bytesRead, cmdBytesLeft); 506 507 schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay); 508} 509 510void 511IdeDisk::doDmaWrite() 512{ 513 if (dmaAborted) { 514 DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n"); 515 if (dmaWriteCG) 516 delete dmaWriteCG; 517 dmaWriteCG = NULL; 518 updateState(ACT_CMD_ERROR); 519 return; 520 } 521 if (!dmaWriteCG) { 522 // clear out the data buffer 523 dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(), 524 curPrd.getByteCount(), TheISA::PageBytes); 525 } 526 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) { 527 schedule(dmaWriteWaitEvent, curTick() + DMA_BACKOFF_PERIOD); 528 DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n"); 529 return; 530 } else if (!dmaWriteCG->done()) { 531 assert(dmaWriteCG->complete() < MAX_DMA_SIZE); 532 ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(), 533 &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete()); 534 DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n", 535 curPrd.getByteCount(), curPrd.getEOT()); 536 dmaWriteBytes += dmaWriteCG->size(); 537 dmaWriteTxs++; 538 if (dmaWriteCG->size() == TheISA::PageBytes) 539 dmaWriteFullPages++; 540 dmaWriteCG->next(); 541 } else { 542 DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n", 543 curPrd.getByteCount(), curPrd.getEOT()); 544 assert(dmaWriteCG->done()); 545 delete dmaWriteCG; 546 dmaWriteCG = NULL; 547 dmaWriteDone(); 548 } 549} 550 551void 552IdeDisk::dmaWriteDone() 553{ 554 DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n", 555 curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft); 556 // check for the EOT 557 if (curPrd.getEOT()) { 558 assert(cmdBytesLeft == 0); 559 dmaState = Dma_Idle; 560 updateState(ACT_DMA_DONE); 561 } else { 562 doDmaTransfer(); 563 } 564} 565 566//// 567// Disk utility routines 568/// 569 570void 571IdeDisk::readDisk(uint32_t sector, uint8_t *data) 572{ 573 uint32_t bytesRead = image->read(data, sector); 574 575 if (bytesRead != SectorSize) 576 panic("Can't read from %s. Only %d of %d read. errno=%d\n", 577 name(), bytesRead, SectorSize, errno); 578} 579 580void 581IdeDisk::writeDisk(uint32_t sector, uint8_t *data) 582{ 583 uint32_t bytesWritten = image->write(data, sector); 584 585 if (bytesWritten != SectorSize) 586 panic("Can't write to %s. Only %d of %d written. errno=%d\n", 587 name(), bytesWritten, SectorSize, errno); 588} 589 590//// 591// Setup and handle commands 592//// 593 594void 595IdeDisk::startDma(const uint32_t &prdTableBase) 596{ 597 if (dmaState != Dma_Start) 598 panic("Inconsistent DMA state, should be in Dma_Start!\n"); 599 600 if (devState != Transfer_Data_Dma) 601 panic("Inconsistent device state for DMA start!\n"); 602 603 // PRD base address is given by bits 31:2 604 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); 605 606 dmaState = Dma_Transfer; 607 608 // schedule dma transfer (doDmaTransfer) 609 schedule(dmaTransferEvent, curTick() + 1); 610} 611 612void 613IdeDisk::abortDma() 614{ 615 if (dmaState == Dma_Idle) 616 panic("Inconsistent DMA state, should be Start or Transfer!"); 617 618 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) 619 panic("Inconsistent device state, should be Transfer or Prepare!\n"); 620 621 updateState(ACT_CMD_ERROR); 622} 623 624void 625IdeDisk::startCommand() 626{ 627 DevAction_t action = ACT_NONE; 628 uint32_t size = 0; 629 dmaRead = false; 630 631 // Decode commands 632 switch (cmdReg.command) { 633 // Supported non-data commands 634 case WDSF_READ_NATIVE_MAX: 635 size = (uint32_t)image->size() - 1; 636 cmdReg.sec_num = (size & 0xff); 637 cmdReg.cyl_low = ((size & 0xff00) >> 8); 638 cmdReg.cyl_high = ((size & 0xff0000) >> 16); 639 cmdReg.head = ((size & 0xf000000) >> 24); 640 641 devState = Command_Execution; 642 action = ACT_CMD_COMPLETE; 643 break; 644 645 case WDCC_RECAL: 646 case WDCC_IDP: 647 case WDCC_STANDBY_IMMED: 648 case WDCC_FLUSHCACHE: 649 case WDSF_VERIFY: 650 case WDSF_SEEK: 651 case SET_FEATURES: 652 case WDCC_SETMULTI: 653 case WDCC_IDLE: 654 devState = Command_Execution; 655 action = ACT_CMD_COMPLETE; 656 break; 657 658 // Supported PIO data-in commands 659 case WDCC_IDENTIFY:
|