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