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