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