ide_disk.cc revision 2107
1/* 2 * Copyright (c) 2004-2005 The Regents of The University of Michigan 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer; 9 * redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution; 12 * neither the name of the copyright holders nor the names of its 13 * contributors may be used to endorse or promote products derived from 14 * this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29/** @file 30 * Device model implementation for an IDE disk 31 */ 32 33#include <cerrno> 34#include <cstring> 35#include <deque> 36#include <string> 37 38#include "base/cprintf.hh" // csprintf 39#include "base/trace.hh" 40#include "dev/disk_image.hh" 41#include "dev/ide_disk.hh" 42#include "dev/ide_ctrl.hh" 43#include "dev/tsunami.hh" 44#include "dev/tsunami_pchip.hh" 45#include "mem/functional/physical.hh" 46#include "mem/bus/bus.hh" 47#include "mem/bus/dma_interface.hh" 48#include "mem/bus/pio_interface.hh" 49#include "mem/bus/pio_interface_impl.hh" 50#include "sim/builder.hh" 51#include "sim/sim_object.hh" 52#include "sim/root.hh" 53#include "arch/isa_traits.hh" 54 55using namespace std; 56using namespace TheISA; 57 58IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys, 59 int id, Tick delay) 60 : SimObject(name), ctrl(NULL), image(img), physmem(phys), diskDelay(delay), 61 dmaTransferEvent(this), dmaReadWaitEvent(this), 62 dmaWriteWaitEvent(this), dmaPrdReadEvent(this), 63 dmaReadEvent(this), dmaWriteEvent(this) 64{ 65 // Reset the device state 66 reset(id); 67 68 // fill out the drive ID structure 69 memset(&driveID, 0, sizeof(struct ataparams)); 70 71 // Calculate LBA and C/H/S values 72 uint16_t cylinders; 73 uint8_t heads; 74 uint8_t sectors; 75 76 uint32_t lba_size = image->size(); 77 if (lba_size >= 16383*16*63) { 78 cylinders = 16383; 79 heads = 16; 80 sectors = 63; 81 } else { 82 if (lba_size >= 63) 83 sectors = 63; 84 else 85 sectors = lba_size; 86 87 if ((lba_size / sectors) >= 16) 88 heads = 16; 89 else 90 heads = (lba_size / sectors); 91 92 cylinders = lba_size / (heads * sectors); 93 } 94 95 // Setup the model name 96 strncpy((char *)driveID.atap_model, "5MI EDD si k", 97 sizeof(driveID.atap_model)); 98 // Set the maximum multisector transfer size 99 driveID.atap_multi = MAX_MULTSECT; 100 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled 101 driveID.atap_capabilities1 = 0x7; 102 // UDMA support, EIDE support 103 driveID.atap_extensions = 0x6; 104 // Setup default C/H/S settings 105 driveID.atap_cylinders = cylinders; 106 driveID.atap_sectors = sectors; 107 driveID.atap_heads = heads; 108 // Setup the current multisector transfer size 109 driveID.atap_curmulti = MAX_MULTSECT; 110 driveID.atap_curmulti_valid = 0x1; 111 // Number of sectors on disk 112 driveID.atap_capacity = lba_size; 113 // Multiword DMA mode 2 and below supported 114 driveID.atap_dmamode_supp = 0x400; 115 // Set PIO mode 4 and 3 supported 116 driveID.atap_piomode_supp = 0x3; 117 // Set DMA mode 4 and below supported 118 driveID.atap_udmamode_supp = 0x1f; 119 // Statically set hardware config word 120 driveID.atap_hwreset_res = 0x4001; 121 122 //arbitrary for now... 123 driveID.atap_ata_major = WDC_VER_ATA7; 124} 125 126IdeDisk::~IdeDisk() 127{ 128 // destroy the data buffer 129 delete [] dataBuffer; 130} 131 132void 133IdeDisk::reset(int id) 134{ 135 // initialize the data buffer and shadow registers 136 dataBuffer = new uint8_t[MAX_DMA_SIZE]; 137 138 memset(dataBuffer, 0, MAX_DMA_SIZE); 139 memset(&cmdReg, 0, sizeof(CommandReg_t)); 140 memset(&curPrd.entry, 0, sizeof(PrdEntry_t)); 141 142 dmaInterfaceBytes = 0; 143 curPrdAddr = 0; 144 curSector = 0; 145 cmdBytes = 0; 146 cmdBytesLeft = 0; 147 drqBytesLeft = 0; 148 dmaRead = false; 149 intrPending = false; 150 151 // set the device state to idle 152 dmaState = Dma_Idle; 153 154 if (id == DEV0) { 155 devState = Device_Idle_S; 156 devID = DEV0; 157 } else if (id == DEV1) { 158 devState = Device_Idle_NS; 159 devID = DEV1; 160 } else { 161 panic("Invalid device ID: %#x\n", id); 162 } 163 164 // set the device ready bit 165 status = STATUS_DRDY_BIT; 166 167 /* The error register must be set to 0x1 on start-up to 168 indicate that no diagnostic error was detected */ 169 cmdReg.error = 0x1; 170} 171 172//// 173// Utility functions 174//// 175 176bool 177IdeDisk::isDEVSelect() 178{ 179 return ctrl->isDiskSelected(this); 180} 181 182Addr 183IdeDisk::pciToDma(Addr pciAddr) 184{ 185 if (ctrl) 186 return ctrl->plat->pciToDma(pciAddr); 187 else 188 panic("Access to unset controller!\n"); 189} 190 191uint32_t 192IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft) 193{ 194 uint32_t bytesInPage = 0; 195 196 // First calculate how many bytes could be in the page 197 if (bytesLeft > TheISA::PageBytes) 198 bytesInPage = TheISA::PageBytes; 199 else 200 bytesInPage = bytesLeft; 201 202 // Next, see if we have crossed a page boundary, and adjust 203 Addr upperBound = curAddr + bytesInPage; 204 Addr pageBound = TheISA::TruncPage(curAddr) + TheISA::PageBytes; 205 206 assert(upperBound >= curAddr && "DMA read wraps around address space!\n"); 207 208 if (upperBound >= pageBound) 209 bytesInPage = pageBound - curAddr; 210 211 return bytesInPage; 212} 213 214//// 215// Device registers read/write 216//// 217 218void 219IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data) 220{ 221 DevAction_t action = ACT_NONE; 222 223 switch (reg_type) { 224 case COMMAND_BLOCK: 225 switch (offset) { 226 // Data transfers occur two bytes at a time 227 case DATA_OFFSET: 228 *(uint16_t*)data = cmdReg.data; 229 action = ACT_DATA_READ_SHORT; 230 break; 231 case ERROR_OFFSET: 232 *data = cmdReg.error; 233 break; 234 case NSECTOR_OFFSET: 235 *data = cmdReg.sec_count; 236 break; 237 case SECTOR_OFFSET: 238 *data = cmdReg.sec_num; 239 break; 240 case LCYL_OFFSET: 241 *data = cmdReg.cyl_low; 242 break; 243 case HCYL_OFFSET: 244 *data = cmdReg.cyl_high; 245 break; 246 case DRIVE_OFFSET: 247 *data = cmdReg.drive; 248 break; 249 case STATUS_OFFSET: 250 *data = status; 251 action = ACT_STAT_READ; 252 break; 253 default: 254 panic("Invalid IDE command register offset: %#x\n", offset); 255 } 256 break; 257 case CONTROL_BLOCK: 258 if (offset == ALTSTAT_OFFSET) 259 *data = status; 260 else 261 panic("Invalid IDE control register offset: %#x\n", offset); 262 break; 263 default: 264 panic("Unknown register block!\n"); 265 } 266 267 if (action != ACT_NONE) 268 updateState(action); 269} 270 271void 272IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data) 273{ 274 DevAction_t action = ACT_NONE; 275 276 switch (reg_type) { 277 case COMMAND_BLOCK: 278 switch (offset) { 279 case DATA_OFFSET: 280 cmdReg.data = *(uint16_t*)data; 281 action = ACT_DATA_WRITE_SHORT; 282 break; 283 case FEATURES_OFFSET: 284 break; 285 case NSECTOR_OFFSET: 286 cmdReg.sec_count = *data; 287 break; 288 case SECTOR_OFFSET: 289 cmdReg.sec_num = *data; 290 break; 291 case LCYL_OFFSET: 292 cmdReg.cyl_low = *data; 293 break; 294 case HCYL_OFFSET: 295 cmdReg.cyl_high = *data; 296 break; 297 case DRIVE_OFFSET: 298 cmdReg.drive = *data; 299 action = ACT_SELECT_WRITE; 300 break; 301 case COMMAND_OFFSET: 302 cmdReg.command = *data; 303 action = ACT_CMD_WRITE; 304 break; 305 default: 306 panic("Invalid IDE command register offset: %#x\n", offset); 307 } 308 break; 309 case CONTROL_BLOCK: 310 if (offset == CONTROL_OFFSET) { 311 if (*data & CONTROL_RST_BIT) { 312 // force the device into the reset state 313 devState = Device_Srst; 314 action = ACT_SRST_SET; 315 } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) 316 action = ACT_SRST_CLEAR; 317 318 nIENBit = (*data & CONTROL_IEN_BIT) ? true : false; 319 } 320 else 321 panic("Invalid IDE control register offset: %#x\n", offset); 322 break; 323 default: 324 panic("Unknown register block!\n"); 325 } 326 327 if (action != ACT_NONE) 328 updateState(action); 329} 330 331//// 332// Perform DMA transactions 333//// 334 335void 336IdeDisk::doDmaTransfer() 337{ 338 if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma) 339 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n", 340 dmaState, devState); 341 342 // first read the current PRD 343 if (dmaInterface) { 344 if (dmaInterface->busy()) { 345 // reschedule after waiting period 346 dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 347 return; 348 } 349 350 dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick, 351 &dmaPrdReadEvent); 352 } else { 353 dmaPrdReadDone(); 354 } 355} 356 357void 358IdeDisk::dmaPrdReadDone() 359{ 360 // actually copy the PRD from physical memory 361 memcpy((void *)&curPrd.entry, 362 physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)), 363 sizeof(PrdEntry_t)); 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 doDmaRead(); 376 else 377 doDmaWrite(); 378} 379 380void 381IdeDisk::doDmaRead() 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 if (dmaInterface) { 389 if (dmaInterface->busy()) { 390 // reschedule after waiting period 391 dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 392 return; 393 } 394 395 Addr dmaAddr = pciToDma(curPrd.getBaseAddr()); 396 397 uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(), 398 (uint32_t)curPrd.getByteCount()); 399 400 dmaInterfaceBytes = bytesInPage; 401 402 dmaInterface->doDMA(Read, dmaAddr, bytesInPage, 403 curTick + totalDiskDelay, &dmaReadEvent); 404 } else { 405 // schedule dmaReadEvent with sectorDelay (dmaReadDone) 406 dmaReadEvent.schedule(curTick + totalDiskDelay); 407 } 408} 409 410void 411IdeDisk::dmaReadDone() 412{ 413 414 Addr curAddr = 0, dmaAddr = 0; 415 uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0; 416 417 // continue to use the DMA interface until all pages are read 418 if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) { 419 // see if the interface is busy 420 if (dmaInterface->busy()) { 421 // reschedule after waiting period 422 dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 423 return; 424 } 425 426 uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes; 427 curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes; 428 dmaAddr = pciToDma(curAddr); 429 430 bytesInPage = bytesInDmaPage(curAddr, bytesLeft); 431 dmaInterfaceBytes += bytesInPage; 432 433 dmaInterface->doDMA(Read, dmaAddr, bytesInPage, 434 curTick, &dmaReadEvent); 435 436 return; 437 } 438 439 // set initial address 440 curAddr = curPrd.getBaseAddr(); 441 442 // clear out the data buffer 443 memset(dataBuffer, 0, MAX_DMA_SIZE); 444 445 // read the data from memory via DMA into a data buffer 446 while (bytesWritten < curPrd.getByteCount()) { 447 if (cmdBytesLeft <= 0) 448 panic("DMA data is larger than # of sectors specified\n"); 449 450 dmaAddr = pciToDma(curAddr); 451 452 // calculate how many bytes are in the current page 453 bytesLeft = curPrd.getByteCount() - bytesWritten; 454 bytesInPage = bytesInDmaPage(curAddr, bytesLeft); 455 456 // copy the data from memory into the data buffer 457 memcpy((void *)(dataBuffer + bytesWritten), 458 physmem->dma_addr(dmaAddr, bytesInPage), 459 bytesInPage); 460 461 curAddr += bytesInPage; 462 bytesWritten += bytesInPage; 463 cmdBytesLeft -= bytesInPage; 464 } 465 466 // write the data to the disk image 467 for (bytesWritten = 0; 468 bytesWritten < curPrd.getByteCount(); 469 bytesWritten += SectorSize) { 470 471 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten)); 472 } 473 474 // check for the EOT 475 if (curPrd.getEOT()) { 476 assert(cmdBytesLeft == 0); 477 dmaState = Dma_Idle; 478 updateState(ACT_DMA_DONE); 479 } else { 480 doDmaTransfer(); 481 } 482} 483 484void 485IdeDisk::doDmaWrite() 486{ 487 /** @todo we need to figure out what the delay actually will be */ 488 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize); 489 490 DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n", 491 diskDelay, totalDiskDelay); 492 493 if (dmaInterface) { 494 if (dmaInterface->busy()) { 495 // reschedule after waiting period 496 dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 497 return; 498 } 499 500 Addr dmaAddr = pciToDma(curPrd.getBaseAddr()); 501 502 uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(), 503 (uint32_t)curPrd.getByteCount()); 504 505 dmaInterfaceBytes = bytesInPage; 506 507 dmaInterface->doDMA(WriteInvalidate, dmaAddr, 508 bytesInPage, curTick + totalDiskDelay, 509 &dmaWriteEvent); 510 } else { 511 // schedule event with disk delay (dmaWriteDone) 512 dmaWriteEvent.schedule(curTick + totalDiskDelay); 513 } 514} 515 516void 517IdeDisk::dmaWriteDone() 518{ 519 Addr curAddr = 0, pageAddr = 0, dmaAddr = 0; 520 uint32_t bytesRead = 0, bytesInPage = 0; 521 522 // continue to use the DMA interface until all pages are read 523 if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) { 524 // see if the interface is busy 525 if (dmaInterface->busy()) { 526 // reschedule after waiting period 527 dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD); 528 return; 529 } 530 531 uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes; 532 curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes; 533 dmaAddr = pciToDma(curAddr); 534 535 bytesInPage = bytesInDmaPage(curAddr, bytesLeft); 536 dmaInterfaceBytes += bytesInPage; 537 538 dmaInterface->doDMA(WriteInvalidate, dmaAddr, 539 bytesInPage, curTick, 540 &dmaWriteEvent); 541 542 return; 543 } 544 545 // setup the initial page and DMA address 546 curAddr = curPrd.getBaseAddr(); 547 pageAddr = TheISA::TruncPage(curAddr); 548 dmaAddr = pciToDma(curAddr); 549 550 // clear out the data buffer 551 memset(dataBuffer, 0, MAX_DMA_SIZE); 552 553 while (bytesRead < curPrd.getByteCount()) { 554 // see if we have crossed into a new page 555 if (pageAddr != TheISA::TruncPage(curAddr)) { 556 // write the data to memory 557 memcpy(physmem->dma_addr(dmaAddr, bytesInPage), 558 (void *)(dataBuffer + (bytesRead - bytesInPage)), 559 bytesInPage); 560 561 // update the DMA address and page address 562 pageAddr = TheISA::TruncPage(curAddr); 563 dmaAddr = pciToDma(curAddr); 564 565 bytesInPage = 0; 566 } 567 568 if (cmdBytesLeft <= 0) 569 panic("DMA requested data is larger than # sectors specified\n"); 570 571 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead)); 572 573 curAddr += SectorSize; 574 bytesRead += SectorSize; 575 bytesInPage += SectorSize; 576 cmdBytesLeft -= SectorSize; 577 } 578 579 // write the last page worth read to memory 580 if (bytesInPage != 0) { 581 memcpy(physmem->dma_addr(dmaAddr, bytesInPage), 582 (void *)(dataBuffer + (bytesRead - bytesInPage)), 583 bytesInPage); 584 } 585 586 // check for the EOT 587 if (curPrd.getEOT()) { 588 assert(cmdBytesLeft == 0); 589 dmaState = Dma_Idle; 590 updateState(ACT_DMA_DONE); 591 } else { 592 doDmaTransfer(); 593 } 594} 595 596//// 597// Disk utility routines 598/// 599 600void 601IdeDisk::readDisk(uint32_t sector, uint8_t *data) 602{ 603 uint32_t bytesRead = image->read(data, sector); 604 605 if (bytesRead != SectorSize) 606 panic("Can't read from %s. Only %d of %d read. errno=%d\n", 607 name(), bytesRead, SectorSize, errno); 608} 609 610void 611IdeDisk::writeDisk(uint32_t sector, uint8_t *data) 612{ 613 uint32_t bytesWritten = image->write(data, sector); 614 615 if (bytesWritten != SectorSize) 616 panic("Can't write to %s. Only %d of %d written. errno=%d\n", 617 name(), bytesWritten, SectorSize, errno); 618} 619 620//// 621// Setup and handle commands 622//// 623 624void 625IdeDisk::startDma(const uint32_t &prdTableBase) 626{ 627 if (dmaState != Dma_Start) 628 panic("Inconsistent DMA state, should be in Dma_Start!\n"); 629 630 if (devState != Transfer_Data_Dma) 631 panic("Inconsistent device state for DMA start!\n"); 632 633 // PRD base address is given by bits 31:2 634 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3))); 635 636 dmaState = Dma_Transfer; 637 638 // schedule dma transfer (doDmaTransfer) 639 dmaTransferEvent.schedule(curTick + 1); 640} 641 642void 643IdeDisk::abortDma() 644{ 645 if (dmaState == Dma_Idle) 646 panic("Inconsistent DMA state, should be Start or Transfer!"); 647 648 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma) 649 panic("Inconsistent device state, should be Transfer or Prepare!\n"); 650 651 updateState(ACT_CMD_ERROR); 652} 653 654void 655IdeDisk::startCommand() 656{ 657 DevAction_t action = ACT_NONE; 658 uint32_t size = 0; 659 dmaRead = false; 660 661 // Decode commands 662 switch (cmdReg.command) { 663 // Supported non-data commands 664 case WDSF_READ_NATIVE_MAX: 665 size = image->size() - 1; 666 cmdReg.sec_num = (size & 0xff); 667 cmdReg.cyl_low = ((size & 0xff00) >> 8); 668 cmdReg.cyl_high = ((size & 0xff0000) >> 16); 669 cmdReg.head = ((size & 0xf000000) >> 24); 670 671 devState = Command_Execution; 672 action = ACT_CMD_COMPLETE; 673 break; 674 675 case WDCC_RECAL: 676 case WDCC_IDP: 677 case WDCC_STANDBY_IMMED: 678 case WDCC_FLUSHCACHE: 679 case WDSF_VERIFY: 680 case WDSF_SEEK: 681 case SET_FEATURES: 682 case WDCC_SETMULTI: 683 devState = Command_Execution; 684 action = ACT_CMD_COMPLETE; 685 break; 686 687 // Supported PIO data-in commands 688 case WDCC_IDENTIFY: 689 cmdBytes = cmdBytesLeft = sizeof(struct ataparams); 690 devState = Prepare_Data_In; 691 action = ACT_DATA_READY; 692 break; 693 694 case WDCC_READMULTI: 695 case WDCC_READ: 696 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 697 panic("Attempt to perform CHS access, only supports LBA\n"); 698 699 if (cmdReg.sec_count == 0) 700 cmdBytes = cmdBytesLeft = (256 * SectorSize); 701 else 702 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 703 704 curSector = getLBABase(); 705 706 /** @todo make this a scheduled event to simulate disk delay */ 707 devState = Prepare_Data_In; 708 action = ACT_DATA_READY; 709 break; 710 711 // Supported PIO data-out commands 712 case WDCC_WRITEMULTI: 713 case WDCC_WRITE: 714 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 715 panic("Attempt to perform CHS access, only supports LBA\n"); 716 717 if (cmdReg.sec_count == 0) 718 cmdBytes = cmdBytesLeft = (256 * SectorSize); 719 else 720 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 721 722 curSector = getLBABase(); 723 724 devState = Prepare_Data_Out; 725 action = ACT_DATA_READY; 726 break; 727 728 // Supported DMA commands 729 case WDCC_WRITEDMA: 730 dmaRead = true; // a write to the disk is a DMA read from memory 731 case WDCC_READDMA: 732 if (!(cmdReg.drive & DRIVE_LBA_BIT)) 733 panic("Attempt to perform CHS access, only supports LBA\n"); 734 735 if (cmdReg.sec_count == 0) 736 cmdBytes = cmdBytesLeft = (256 * SectorSize); 737 else 738 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize); 739 740 curSector = getLBABase(); 741 742 devState = Prepare_Data_Dma; 743 action = ACT_DMA_READY; 744 break; 745 746 default: 747 panic("Unsupported ATA command: %#x\n", cmdReg.command); 748 } 749 750 if (action != ACT_NONE) { 751 // set the BSY bit 752 status |= STATUS_BSY_BIT; 753 // clear the DRQ bit 754 status &= ~STATUS_DRQ_BIT; 755 // clear the DF bit 756 status &= ~STATUS_DF_BIT; 757 758 updateState(action); 759 } 760} 761 762//// 763// Handle setting and clearing interrupts 764//// 765 766void 767IdeDisk::intrPost() 768{ 769 DPRINTF(IdeDisk, "Posting Interrupt\n"); 770 if (intrPending) 771 panic("Attempt to post an interrupt with one pending\n"); 772 773 intrPending = true; 774 775 // talk to controller to set interrupt 776 if (ctrl) { 777 ctrl->bmi_regs.bmis0 |= IDEINTS; 778 ctrl->intrPost(); 779 } 780} 781 782void 783IdeDisk::intrClear() 784{ 785 DPRINTF(IdeDisk, "Clearing Interrupt\n"); 786 if (!intrPending) 787 panic("Attempt to clear a non-pending interrupt\n"); 788 789 intrPending = false; 790 791 // talk to controller to clear interrupt 792 if (ctrl) 793 ctrl->intrClear(); 794} 795 796//// 797// Manage the device internal state machine 798//// 799 800void 801IdeDisk::updateState(DevAction_t action) 802{ 803 switch (devState) { 804 case Device_Srst: 805 if (action == ACT_SRST_SET) { 806 // set the BSY bit 807 status |= STATUS_BSY_BIT; 808 } else if (action == ACT_SRST_CLEAR) { 809 // clear the BSY bit 810 status &= ~STATUS_BSY_BIT; 811 812 // reset the device state 813 reset(devID); 814 } 815 break; 816 817 case Device_Idle_S: 818 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 819 devState = Device_Idle_NS; 820 } else if (action == ACT_CMD_WRITE) { 821 startCommand(); 822 } 823 824 break; 825 826 case Device_Idle_SI: 827 if (action == ACT_SELECT_WRITE && !isDEVSelect()) { 828 devState = Device_Idle_NS; 829 intrClear(); 830 } else if (action == ACT_STAT_READ || isIENSet()) { 831 devState = Device_Idle_S; 832 intrClear(); 833 } else if (action == ACT_CMD_WRITE) { 834 intrClear(); 835 startCommand(); 836 } 837 838 break; 839 840 case Device_Idle_NS: 841 if (action == ACT_SELECT_WRITE && isDEVSelect()) { 842 if (!isIENSet() && intrPending) { 843 devState = Device_Idle_SI; 844 intrPost(); 845 } 846 if (isIENSet() || !intrPending) { 847 devState = Device_Idle_S; 848 } 849 } 850 break; 851 852 case Command_Execution: 853 if (action == ACT_CMD_COMPLETE) { 854 // clear the BSY bit 855 setComplete(); 856 857 if (!isIENSet()) { 858 devState = Device_Idle_SI; 859 intrPost(); 860 } else { 861 devState = Device_Idle_S; 862 } 863 } 864 break; 865 866 case Prepare_Data_In: 867 if (action == ACT_CMD_ERROR) { 868 // clear the BSY bit 869 setComplete(); 870 871 if (!isIENSet()) { 872 devState = Device_Idle_SI; 873 intrPost(); 874 } else { 875 devState = Device_Idle_S; 876 } 877 } else if (action == ACT_DATA_READY) { 878 // clear the BSY bit 879 status &= ~STATUS_BSY_BIT; 880 // set the DRQ bit 881 status |= STATUS_DRQ_BIT; 882 883 // copy the data into the data buffer 884 if (cmdReg.command == WDCC_IDENTIFY) { 885 // Reset the drqBytes for this block 886 drqBytesLeft = sizeof(struct ataparams); 887 888 memcpy((void *)dataBuffer, (void *)&driveID, 889 sizeof(struct ataparams)); 890 } else { 891 // Reset the drqBytes for this block 892 drqBytesLeft = SectorSize; 893 894 readDisk(curSector++, dataBuffer); 895 } 896 897 // put the first two bytes into the data register 898 memcpy((void *)&cmdReg.data, (void *)dataBuffer, 899 sizeof(uint16_t)); 900 901 if (!isIENSet()) { 902 devState = Data_Ready_INTRQ_In; 903 intrPost(); 904 } else { 905 devState = Transfer_Data_In; 906 } 907 } 908 break; 909 910 case Data_Ready_INTRQ_In: 911 if (action == ACT_STAT_READ) { 912 devState = Transfer_Data_In; 913 intrClear(); 914 } 915 break; 916 917 case Transfer_Data_In: 918 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) { 919 if (action == ACT_DATA_READ_BYTE) { 920 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n"); 921 } else { 922 drqBytesLeft -= 2; 923 cmdBytesLeft -= 2; 924 925 // copy next short into data registers 926 if (drqBytesLeft) 927 memcpy((void *)&cmdReg.data, 928 (void *)&dataBuffer[SectorSize - drqBytesLeft], 929 sizeof(uint16_t)); 930 } 931 932 if (drqBytesLeft == 0) { 933 if (cmdBytesLeft == 0) { 934 // Clear the BSY bit 935 setComplete(); 936 devState = Device_Idle_S; 937 } else { 938 devState = Prepare_Data_In; 939 // set the BSY_BIT 940 status |= STATUS_BSY_BIT; 941 // clear the DRQ_BIT 942 status &= ~STATUS_DRQ_BIT; 943 944 /** @todo change this to a scheduled event to simulate 945 disk delay */ 946 updateState(ACT_DATA_READY); 947 } 948 } 949 } 950 break; 951 952 case Prepare_Data_Out: 953 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) { 954 // clear the BSY bit 955 setComplete(); 956 957 if (!isIENSet()) { 958 devState = Device_Idle_SI; 959 intrPost(); 960 } else { 961 devState = Device_Idle_S; 962 } 963 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) { 964 // clear the BSY bit 965 status &= ~STATUS_BSY_BIT; 966 // set the DRQ bit 967 status |= STATUS_DRQ_BIT; 968 969 // clear the data buffer to get it ready for writes 970 memset(dataBuffer, 0, MAX_DMA_SIZE); 971 972 // reset the drqBytes for this block 973 drqBytesLeft = SectorSize; 974 975 if (cmdBytesLeft == cmdBytes || isIENSet()) { 976 devState = Transfer_Data_Out; 977 } else { 978 devState = Data_Ready_INTRQ_Out; 979 intrPost(); 980 } 981 } 982 break; 983 984 case Data_Ready_INTRQ_Out: 985 if (action == ACT_STAT_READ) { 986 devState = Transfer_Data_Out; 987 intrClear(); 988 } 989 break; 990 991 case Transfer_Data_Out: 992 if (action == ACT_DATA_WRITE_BYTE || 993 action == ACT_DATA_WRITE_SHORT) { 994 995 if (action == ACT_DATA_READ_BYTE) { 996 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n"); 997 } else { 998 // copy the latest short into the data buffer 999 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft], 1000 (void *)&cmdReg.data, 1001 sizeof(uint16_t)); 1002 1003 drqBytesLeft -= 2; 1004 cmdBytesLeft -= 2; 1005 } 1006 1007 if (drqBytesLeft == 0) { 1008 // copy the block to the disk 1009 writeDisk(curSector++, dataBuffer); 1010 1011 // set the BSY bit 1012 status |= STATUS_BSY_BIT; 1013 // set the seek bit 1014 status |= STATUS_SEEK_BIT; 1015 // clear the DRQ bit 1016 status &= ~STATUS_DRQ_BIT; 1017 1018 devState = Prepare_Data_Out; 1019 1020 /** @todo change this to a scheduled event to simulate 1021 disk delay */ 1022 updateState(ACT_DATA_READY); 1023 } 1024 } 1025 break; 1026 1027 case Prepare_Data_Dma: 1028 if (action == ACT_CMD_ERROR) { 1029 // clear the BSY bit 1030 setComplete(); 1031 1032 if (!isIENSet()) { 1033 devState = Device_Idle_SI; 1034 intrPost(); 1035 } else { 1036 devState = Device_Idle_S; 1037 } 1038 } else if (action == ACT_DMA_READY) { 1039 // clear the BSY bit 1040 status &= ~STATUS_BSY_BIT; 1041 // set the DRQ bit 1042 status |= STATUS_DRQ_BIT; 1043 1044 devState = Transfer_Data_Dma; 1045 1046 if (dmaState != Dma_Idle) 1047 panic("Inconsistent DMA state, should be Dma_Idle\n"); 1048 1049 dmaState = Dma_Start; 1050 // wait for the write to the DMA start bit 1051 } 1052 break; 1053 1054 case Transfer_Data_Dma: 1055 if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) { 1056 // clear the BSY bit 1057 setComplete(); 1058 // set the seek bit 1059 status |= STATUS_SEEK_BIT; 1060 // clear the controller state for DMA transfer 1061 ctrl->setDmaComplete(this); 1062 1063 if (!isIENSet()) { 1064 devState = Device_Idle_SI; 1065 intrPost(); 1066 } else { 1067 devState = Device_Idle_S; 1068 } 1069 } 1070 break; 1071 1072 default: 1073 panic("Unknown IDE device state: %#x\n", devState); 1074 } 1075} 1076 1077void 1078IdeDisk::serialize(ostream &os) 1079{ 1080 // Check all outstanding events to see if they are scheduled 1081 // these are all mutually exclusive 1082 Tick reschedule = 0; 1083 Events_t event = None; 1084 1085 int eventCount = 0; 1086 1087 if (dmaTransferEvent.scheduled()) { 1088 reschedule = dmaTransferEvent.when(); 1089 event = Transfer; 1090 eventCount++; 1091 } 1092 if (dmaReadWaitEvent.scheduled()) { 1093 reschedule = dmaReadWaitEvent.when(); 1094 event = ReadWait; 1095 eventCount++; 1096 } 1097 if (dmaWriteWaitEvent.scheduled()) { 1098 reschedule = dmaWriteWaitEvent.when(); 1099 event = WriteWait; 1100 eventCount++; 1101 } 1102 if (dmaPrdReadEvent.scheduled()) { 1103 reschedule = dmaPrdReadEvent.when(); 1104 event = PrdRead; 1105 eventCount++; 1106 } 1107 if (dmaReadEvent.scheduled()) { 1108 reschedule = dmaReadEvent.when(); 1109 event = DmaRead; 1110 eventCount++; 1111 } 1112 if (dmaWriteEvent.scheduled()) { 1113 reschedule = dmaWriteEvent.when(); 1114 event = DmaWrite; 1115 eventCount++; 1116 } 1117 1118 assert(eventCount <= 1); 1119 1120 SERIALIZE_SCALAR(reschedule); 1121 SERIALIZE_ENUM(event); 1122 1123 // Serialize device registers 1124 SERIALIZE_SCALAR(cmdReg.data); 1125 SERIALIZE_SCALAR(cmdReg.sec_count); 1126 SERIALIZE_SCALAR(cmdReg.sec_num); 1127 SERIALIZE_SCALAR(cmdReg.cyl_low); 1128 SERIALIZE_SCALAR(cmdReg.cyl_high); 1129 SERIALIZE_SCALAR(cmdReg.drive); 1130 SERIALIZE_SCALAR(cmdReg.command); 1131 SERIALIZE_SCALAR(status); 1132 SERIALIZE_SCALAR(nIENBit); 1133 SERIALIZE_SCALAR(devID); 1134 1135 // Serialize the PRD related information 1136 SERIALIZE_SCALAR(curPrd.entry.baseAddr); 1137 SERIALIZE_SCALAR(curPrd.entry.byteCount); 1138 SERIALIZE_SCALAR(curPrd.entry.endOfTable); 1139 SERIALIZE_SCALAR(curPrdAddr); 1140 1141 // Serialize current transfer related information 1142 SERIALIZE_SCALAR(cmdBytesLeft); 1143 SERIALIZE_SCALAR(cmdBytes); 1144 SERIALIZE_SCALAR(drqBytesLeft); 1145 SERIALIZE_SCALAR(curSector); 1146 SERIALIZE_SCALAR(dmaRead); 1147 SERIALIZE_SCALAR(dmaInterfaceBytes); 1148 SERIALIZE_SCALAR(intrPending); 1149 SERIALIZE_ENUM(devState); 1150 SERIALIZE_ENUM(dmaState); 1151 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1152} 1153 1154void 1155IdeDisk::unserialize(Checkpoint *cp, const string §ion) 1156{ 1157 // Reschedule events that were outstanding 1158 // these are all mutually exclusive 1159 Tick reschedule = 0; 1160 Events_t event = None; 1161 1162 UNSERIALIZE_SCALAR(reschedule); 1163 UNSERIALIZE_ENUM(event); 1164 1165 switch (event) { 1166 case None : break; 1167 case Transfer : dmaTransferEvent.schedule(reschedule); break; 1168 case ReadWait : dmaReadWaitEvent.schedule(reschedule); break; 1169 case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break; 1170 case PrdRead : dmaPrdReadEvent.schedule(reschedule); break; 1171 case DmaRead : dmaReadEvent.schedule(reschedule); break; 1172 case DmaWrite : dmaWriteEvent.schedule(reschedule); break; 1173 } 1174 1175 // Unserialize device registers 1176 UNSERIALIZE_SCALAR(cmdReg.data); 1177 UNSERIALIZE_SCALAR(cmdReg.sec_count); 1178 UNSERIALIZE_SCALAR(cmdReg.sec_num); 1179 UNSERIALIZE_SCALAR(cmdReg.cyl_low); 1180 UNSERIALIZE_SCALAR(cmdReg.cyl_high); 1181 UNSERIALIZE_SCALAR(cmdReg.drive); 1182 UNSERIALIZE_SCALAR(cmdReg.command); 1183 UNSERIALIZE_SCALAR(status); 1184 UNSERIALIZE_SCALAR(nIENBit); 1185 UNSERIALIZE_SCALAR(devID); 1186 1187 // Unserialize the PRD related information 1188 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr); 1189 UNSERIALIZE_SCALAR(curPrd.entry.byteCount); 1190 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable); 1191 UNSERIALIZE_SCALAR(curPrdAddr); 1192 1193 // Unserialize current transfer related information 1194 UNSERIALIZE_SCALAR(cmdBytes); 1195 UNSERIALIZE_SCALAR(cmdBytesLeft); 1196 UNSERIALIZE_SCALAR(drqBytesLeft); 1197 UNSERIALIZE_SCALAR(curSector); 1198 UNSERIALIZE_SCALAR(dmaRead); 1199 UNSERIALIZE_SCALAR(dmaInterfaceBytes); 1200 UNSERIALIZE_SCALAR(intrPending); 1201 UNSERIALIZE_ENUM(devState); 1202 UNSERIALIZE_ENUM(dmaState); 1203 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE); 1204} 1205 1206#ifndef DOXYGEN_SHOULD_SKIP_THIS 1207 1208enum DriveID { master, slave }; 1209static const char *DriveID_strings[] = { "master", "slave" }; 1210BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 1211 1212 SimObjectParam<DiskImage *> image; 1213 SimObjectParam<PhysicalMemory *> physmem; 1214 SimpleEnumParam<DriveID> driveID; 1215 Param<int> delay; 1216 1217END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk) 1218 1219BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk) 1220 1221 INIT_PARAM(image, "Disk image"), 1222 INIT_PARAM(physmem, "Physical memory"), 1223 INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings), 1224 INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1) 1225 1226END_INIT_SIM_OBJECT_PARAMS(IdeDisk) 1227 1228 1229CREATE_SIM_OBJECT(IdeDisk) 1230{ 1231 return new IdeDisk(getInstanceName(), image, physmem, driveID, delay); 1232} 1233 1234REGISTER_SIM_OBJECT("IdeDisk", IdeDisk) 1235 1236#endif //DOXYGEN_SHOULD_SKIP_THIS 1237