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