gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ide_disk.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2013 ARM Limited
3  * All rights reserved
4  *
5  * The license below extends only to copyright in the software and shall
6  * not be construed as granting a license to any other intellectual
7  * property including but not limited to intellectual property relating
8  * to a hardware implementation of the functionality of the software
9  * licensed hereunder. You may use the software subject to the license
10  * terms below provided that you ensure that this notice is replicated
11  * unmodified and in its entirety in all distributions of the software,
12  * modified or unmodified, in source code or in binary form.
13  *
14  * Copyright (c) 2004-2005 The Regents of The University of Michigan
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions are
19  * met: redistributions of source code must retain the above copyright
20  * notice, this list of conditions and the following disclaimer;
21  * redistributions in binary form must reproduce the above copyright
22  * notice, this list of conditions and the following disclaimer in the
23  * documentation and/or other materials provided with the distribution;
24  * neither the name of the copyright holders nor the names of its
25  * contributors may be used to endorse or promote products derived from
26  * this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  *
40  * Authors: Andrew Schultz
41  * Ali Saidi
42  */
43 
48 #include "dev/storage/ide_disk.hh"
49 
50 #include <cerrno>
51 #include <cstring>
52 #include <deque>
53 #include <string>
54 
55 #include "arch/isa_traits.hh"
56 #include "base/chunk_generator.hh"
57 #include "base/cprintf.hh" // csprintf
58 #include "base/trace.hh"
59 #include "config/the_isa.hh"
60 #include "debug/IdeDisk.hh"
62 #include "dev/storage/ide_ctrl.hh"
63 #include "sim/core.hh"
64 #include "sim/sim_object.hh"
65 
66 using namespace std;
67 using namespace TheISA;
68 
70  : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay),
71  dmaTransferEvent(this), dmaReadCG(NULL), dmaReadWaitEvent(this),
72  dmaWriteCG(NULL), dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
73  dmaReadEvent(this), dmaWriteEvent(this)
74 {
75  // Reset the device state
76  reset(p->driveID);
77 
78  // fill out the drive ID structure
79  memset(&driveID, 0, sizeof(struct ataparams));
80 
81  // Calculate LBA and C/H/S values
82  uint16_t cylinders;
83  uint8_t heads;
84  uint8_t sectors;
85 
86  uint32_t lba_size = image->size();
87  if (lba_size >= 16383*16*63) {
88  cylinders = 16383;
89  heads = 16;
90  sectors = 63;
91  } else {
92  if (lba_size >= 63)
93  sectors = 63;
94  else if (lba_size == 0)
95  panic("Bad IDE image size: 0\n");
96  else
97  sectors = lba_size;
98 
99  if ((lba_size / sectors) >= 16)
100  heads = 16;
101  else
102  heads = (lba_size / sectors);
103 
104  cylinders = lba_size / (heads * sectors);
105  }
106 
107  // Setup the model name
108  strncpy((char *)driveID.atap_model, "5MI EDD si k",
109  sizeof(driveID.atap_model));
110  // Set the maximum multisector transfer size
112  // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
114  // UDMA support, EIDE support
115  driveID.atap_extensions = 0x6;
116  // Setup default C/H/S settings
117  driveID.atap_cylinders = cylinders;
118  driveID.atap_sectors = sectors;
119  driveID.atap_heads = heads;
120  // Setup the current multisector transfer size
123  // Number of sectors on disk
124  driveID.atap_capacity = lba_size;
125  // Multiword DMA mode 2 and below supported
127  // Set PIO mode 4 and 3 supported
129  // Set DMA mode 4 and below supported
131  // Statically set hardware config word
132  driveID.atap_hwreset_res = 0x4001;
133 
134  //arbitrary for now...
136 }
137 
139 {
140  // destroy the data buffer
141  delete [] dataBuffer;
142 }
143 
144 void
146 {
147  // initialize the data buffer and shadow registers
148  dataBuffer = new uint8_t[MAX_DMA_SIZE];
149 
150  memset(dataBuffer, 0, MAX_DMA_SIZE);
151  memset(&cmdReg, 0, sizeof(CommandReg_t));
152  memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
153 
154  curPrdAddr = 0;
155  curSector = 0;
156  cmdBytes = 0;
157  cmdBytesLeft = 0;
158  drqBytesLeft = 0;
159  dmaRead = false;
160  intrPending = false;
161  dmaAborted = false;
162 
163  // set the device state to idle
164  dmaState = Dma_Idle;
165 
166  if (id == DEV0) {
168  devID = DEV0;
169  } else if (id == DEV1) {
171  devID = DEV1;
172  } else {
173  panic("Invalid device ID: %#x\n", id);
174  }
175 
176  // set the device ready bit
178 
179  /* The error register must be set to 0x1 on start-up to
180  indicate that no diagnostic error was detected */
181  cmdReg.error = 0x1;
182 }
183 
185 // Utility functions
187 
188 bool
190 {
191  return ctrl->isDiskSelected(this);
192 }
193 
194 Addr
196 {
197  if (ctrl)
198  return ctrl->pciToDma(pciAddr);
199  else
200  panic("Access to unset controller!\n");
201 }
202 
204 // Device registers read/write
206 
207 void
208 IdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
209 {
210  if (offset == DATA_OFFSET) {
211  if (size == sizeof(uint16_t)) {
212  *(uint16_t *)data = cmdReg.data;
213  } else if (size == sizeof(uint32_t)) {
214  *(uint16_t *)data = cmdReg.data;
216  *((uint16_t *)data + 1) = cmdReg.data;
217  } else {
218  panic("Data read of unsupported size %d.\n", size);
219  }
221  return;
222  }
223  assert(size == sizeof(uint8_t));
224  switch (offset) {
225  case ERROR_OFFSET:
226  *data = cmdReg.error;
227  break;
228  case NSECTOR_OFFSET:
229  *data = cmdReg.sec_count;
230  break;
231  case SECTOR_OFFSET:
232  *data = cmdReg.sec_num;
233  break;
234  case LCYL_OFFSET:
235  *data = cmdReg.cyl_low;
236  break;
237  case HCYL_OFFSET:
238  *data = cmdReg.cyl_high;
239  break;
240  case DRIVE_OFFSET:
241  *data = cmdReg.drive;
242  break;
243  case STATUS_OFFSET:
244  *data = status;
246  break;
247  default:
248  panic("Invalid IDE command register offset: %#x\n", offset);
249  }
250  DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
251 }
252 
253 void
254 IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
255 {
256  assert(size == sizeof(uint8_t));
257  *data = status;
258  if (offset != ALTSTAT_OFFSET)
259  panic("Invalid IDE control register offset: %#x\n", offset);
260  DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
261 }
262 
263 void
264 IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
265 {
266  if (offset == DATA_OFFSET) {
267  if (size == sizeof(uint16_t)) {
268  cmdReg.data = *(const uint16_t *)data;
269  } else if (size == sizeof(uint32_t)) {
270  cmdReg.data = *(const uint16_t *)data;
272  cmdReg.data = *((const uint16_t *)data + 1);
273  } else {
274  panic("Data write of unsupported size %d.\n", size);
275  }
277  return;
278  }
279 
280  assert(size == sizeof(uint8_t));
281  switch (offset) {
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;
299  break;
300  case COMMAND_OFFSET:
301  cmdReg.command = *data;
303  break;
304  default:
305  panic("Invalid IDE command register offset: %#x\n", offset);
306  }
307  DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
308  (uint32_t)*data);
309 }
310 
311 void
312 IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
313 {
314  if (offset != CONTROL_OFFSET)
315  panic("Invalid IDE control register offset: %#x\n", offset);
316 
317  if (*data & CONTROL_RST_BIT) {
318  // force the device into the reset state
321  } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
323  }
324 
325  nIENBit = *data & CONTROL_IEN_BIT;
326 
327  DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
328  (uint32_t)*data);
329 }
330 
332 // Perform DMA transactions
334 
335 void
337 {
338  if (dmaAborted) {
339  DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n");
341  return;
342  }
343 
345  panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
346  dmaState, devState);
347 
350  return;
351  } else
353  (uint8_t*)&curPrd.entry);
354 }
355 
356 void
358 {
359  if (dmaAborted) {
360  DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n");
362  return;
363  }
364 
366  "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
369  curPrd.getEOT(), curSector);
370 
371  // the prd pointer has already been translated, so just do an increment
372  curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
373 
374  if (dmaRead)
375  doDmaDataRead();
376  else
377  doDmaDataWrite();
378 }
379 
380 void
382 {
384  Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
385 
386  DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
387  diskDelay, totalDiskDelay);
388 
389  schedule(dmaReadWaitEvent, curTick() + totalDiskDelay);
390 }
391 
392 void
394 {
396 
397  using namespace Stats;
399  .name(name() + ".dma_read_full_pages")
400  .desc("Number of full page size DMA reads (not PRD).")
401  ;
403  .name(name() + ".dma_read_bytes")
404  .desc("Number of bytes transfered via DMA reads (not PRD).")
405  ;
406  dmaReadTxs
407  .name(name() + ".dma_read_txs")
408  .desc("Number of DMA read transactions (not PRD).")
409  ;
410 
412  .name(name() + ".dma_write_full_pages")
413  .desc("Number of full page size DMA writes.")
414  ;
416  .name(name() + ".dma_write_bytes")
417  .desc("Number of bytes transfered via DMA writes.")
418  ;
420  .name(name() + ".dma_write_txs")
421  .desc("Number of DMA write transactions.")
422  ;
423 }
424 
425 void
427 {
428  if (dmaAborted) {
429  DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
430  if (dmaReadCG)
431  delete dmaReadCG;
432  dmaReadCG = NULL;
434  return;
435  }
436 
437  if (!dmaReadCG) {
438  // clear out the data buffer
439  memset(dataBuffer, 0, MAX_DMA_SIZE);
442 
443  }
446  return;
447  } else if (!dmaReadCG->done()) {
448  assert(dmaReadCG->complete() < MAX_DMA_SIZE);
452  dmaReadTxs++;
453  if (dmaReadCG->size() == TheISA::PageBytes)
455  dmaReadCG->next();
456  } else {
457  assert(dmaReadCG->done());
458  delete dmaReadCG;
459  dmaReadCG = NULL;
460  dmaReadDone();
461  }
462 }
463 
464 void
466 {
467  uint32_t bytesWritten = 0;
468 
469  // write the data to the disk image
470  for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
471  bytesWritten += SectorSize) {
472 
474  writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
475  }
476 
477  // check for the EOT
478  if (curPrd.getEOT()) {
479  assert(cmdBytesLeft == 0);
480  dmaState = Dma_Idle;
482  } else {
483  doDmaTransfer();
484  }
485 }
486 
487 void
489 {
491  Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
492  uint32_t bytesRead = 0;
493 
494  DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
495  diskDelay, totalDiskDelay);
496 
497  memset(dataBuffer, 0, MAX_DMA_SIZE);
498  assert(cmdBytesLeft <= MAX_DMA_SIZE);
499  while (bytesRead < curPrd.getByteCount()) {
500  readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
501  bytesRead += SectorSize;
503  }
504  DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
505  bytesRead, cmdBytesLeft);
506 
507  schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
508 }
509 
510 void
512 {
513  if (dmaAborted) {
514  DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
515  if (dmaWriteCG)
516  delete dmaWriteCG;
517  dmaWriteCG = NULL;
519  return;
520  }
521  if (!dmaWriteCG) {
522  // clear out the data buffer
525  }
528  DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
529  return;
530  } else if (!dmaWriteCG->done()) {
531  assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
534  DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
537  dmaWriteTxs++;
540  dmaWriteCG->next();
541  } else {
542  DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
544  assert(dmaWriteCG->done());
545  delete dmaWriteCG;
546  dmaWriteCG = NULL;
547  dmaWriteDone();
548  }
549 }
550 
551 void
553 {
554  DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
556  // check for the EOT
557  if (curPrd.getEOT()) {
558  assert(cmdBytesLeft == 0);
559  dmaState = Dma_Idle;
561  } else {
562  doDmaTransfer();
563  }
564 }
565 
567 // Disk utility routines
569 
570 void
571 IdeDisk::readDisk(uint32_t sector, uint8_t *data)
572 {
573  uint32_t bytesRead = image->read(data, sector);
574 
575  if (bytesRead != SectorSize)
576  panic("Can't read from %s. Only %d of %d read. errno=%d\n",
577  name(), bytesRead, SectorSize, errno);
578 }
579 
580 void
581 IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
582 {
583  uint32_t bytesWritten = image->write(data, sector);
584 
585  if (bytesWritten != SectorSize)
586  panic("Can't write to %s. Only %d of %d written. errno=%d\n",
587  name(), bytesWritten, SectorSize, errno);
588 }
589 
591 // Setup and handle commands
593 
594 void
595 IdeDisk::startDma(const uint32_t &prdTableBase)
596 {
597  if (dmaState != Dma_Start)
598  panic("Inconsistent DMA state, should be in Dma_Start!\n");
599 
601  panic("Inconsistent device state for DMA start!\n");
602 
603  // PRD base address is given by bits 31:2
604  curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
605 
607 
608  // schedule dma transfer (doDmaTransfer)
610 }
611 
612 void
614 {
615  if (dmaState == Dma_Idle)
616  panic("Inconsistent DMA state, should be Start or Transfer!");
617 
619  panic("Inconsistent device state, should be Transfer or Prepare!\n");
620 
622 }
623 
624 void
626 {
627  DevAction_t action = ACT_NONE;
628  uint32_t size = 0;
629  dmaRead = false;
630 
631  // Decode commands
632  switch (cmdReg.command) {
633  // Supported non-data commands
635  size = (uint32_t)image->size() - 1;
636  cmdReg.sec_num = (size & 0xff);
637  cmdReg.cyl_low = ((size & 0xff00) >> 8);
638  cmdReg.cyl_high = ((size & 0xff0000) >> 16);
639  cmdReg.head = ((size & 0xf000000) >> 24);
640 
642  action = ACT_CMD_COMPLETE;
643  break;
644 
645  case WDCC_RECAL:
646  case WDCC_IDP:
647  case WDCC_STANDBY_IMMED:
648  case WDCC_FLUSHCACHE:
649  case WDSF_VERIFY:
650  case WDSF_SEEK:
651  case SET_FEATURES:
652  case WDCC_SETMULTI:
653  case WDCC_IDLE:
655  action = ACT_CMD_COMPLETE;
656  break;
657 
658  // Supported PIO data-in commands
659  case WDCC_IDENTIFY:
661  cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
663  action = ACT_DATA_READY;
664  break;
665 
666  case WDCC_READMULTI:
667  case WDCC_READ:
668  if (!(cmdReg.drive & DRIVE_LBA_BIT))
669  panic("Attempt to perform CHS access, only supports LBA\n");
670 
671  if (cmdReg.sec_count == 0)
672  cmdBytes = cmdBytesLeft = (256 * SectorSize);
673  else
675 
676  curSector = getLBABase();
677 
680  action = ACT_DATA_READY;
681  break;
682 
683  // Supported PIO data-out commands
684  case WDCC_WRITEMULTI:
685  case WDCC_WRITE:
686  if (!(cmdReg.drive & DRIVE_LBA_BIT))
687  panic("Attempt to perform CHS access, only supports LBA\n");
688 
689  if (cmdReg.sec_count == 0)
690  cmdBytes = cmdBytesLeft = (256 * SectorSize);
691  else
693  DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
694  curSector = getLBABase();
695 
697  action = ACT_DATA_READY;
698  break;
699 
700  // Supported DMA commands
701  case WDCC_WRITEDMA:
702  dmaRead = true; // a write to the disk is a DMA read from memory
703  case WDCC_READDMA:
704  if (!(cmdReg.drive & DRIVE_LBA_BIT))
705  panic("Attempt to perform CHS access, only supports LBA\n");
706 
707  if (cmdReg.sec_count == 0)
708  cmdBytes = cmdBytesLeft = (256 * SectorSize);
709  else
711  DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
712 
713  curSector = getLBABase();
714 
716  action = ACT_DMA_READY;
717  break;
718 
719  default:
720  panic("Unsupported ATA command: %#x\n", cmdReg.command);
721  }
722 
723  if (action != ACT_NONE) {
724  // set the BSY bit
726  // clear the DRQ bit
728  // clear the DF bit
729  status &= ~STATUS_DF_BIT;
730 
731  updateState(action);
732  }
733 }
734 
736 // Handle setting and clearing interrupts
738 
739 void
741 {
742  DPRINTF(IdeDisk, "Posting Interrupt\n");
743  if (intrPending)
744  panic("Attempt to post an interrupt with one pending\n");
745 
746  intrPending = true;
747 
748  // talk to controller to set interrupt
749  if (ctrl) {
750  ctrl->intrPost();
751  }
752 }
753 
754 void
756 {
757  DPRINTF(IdeDisk, "Clearing Interrupt\n");
758  if (!intrPending)
759  panic("Attempt to clear a non-pending interrupt\n");
760 
761  intrPending = false;
762 
763  // talk to controller to clear interrupt
764  if (ctrl)
765  ctrl->intrClear();
766 }
767 
769 // Manage the device internal state machine
771 
772 void
774 {
775  switch (devState) {
776  case Device_Srst:
777  if (action == ACT_SRST_SET) {
778  // set the BSY bit
780  } else if (action == ACT_SRST_CLEAR) {
781  // clear the BSY bit
783 
784  // reset the device state
785  reset(devID);
786  }
787  break;
788 
789  case Device_Idle_S:
790  if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
792  } else if (action == ACT_CMD_WRITE) {
793  startCommand();
794  }
795 
796  break;
797 
798  case Device_Idle_SI:
799  if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
801  intrClear();
802  } else if (action == ACT_STAT_READ || isIENSet()) {
804  intrClear();
805  } else if (action == ACT_CMD_WRITE) {
806  intrClear();
807  startCommand();
808  }
809 
810  break;
811 
812  case Device_Idle_NS:
813  if (action == ACT_SELECT_WRITE && isDEVSelect()) {
814  if (!isIENSet() && intrPending) {
816  intrPost();
817  }
818  if (isIENSet() || !intrPending) {
820  }
821  }
822  break;
823 
824  case Command_Execution:
825  if (action == ACT_CMD_COMPLETE) {
826  // clear the BSY bit
827  setComplete();
828 
829  if (!isIENSet()) {
831  intrPost();
832  } else {
834  }
835  }
836  break;
837 
838  case Prepare_Data_In:
839  if (action == ACT_CMD_ERROR) {
840  // clear the BSY bit
841  setComplete();
842 
843  if (!isIENSet()) {
845  intrPost();
846  } else {
848  }
849  } else if (action == ACT_DATA_READY) {
850  // clear the BSY bit
852  // set the DRQ bit
854 
855  // copy the data into the data buffer
856  if (cmdReg.command == WDCC_IDENTIFY ||
858  // Reset the drqBytes for this block
859  drqBytesLeft = sizeof(struct ataparams);
860 
861  memcpy((void *)dataBuffer, (void *)&driveID,
862  sizeof(struct ataparams));
863  } else {
864  // Reset the drqBytes for this block
866 
868  }
869 
870  // put the first two bytes into the data register
871  memcpy((void *)&cmdReg.data, (void *)dataBuffer,
872  sizeof(uint16_t));
873 
874  if (!isIENSet()) {
876  intrPost();
877  } else {
879  }
880  }
881  break;
882 
883  case Data_Ready_INTRQ_In:
884  if (action == ACT_STAT_READ) {
886  intrClear();
887  }
888  break;
889 
890  case Transfer_Data_In:
891  if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
892  if (action == ACT_DATA_READ_BYTE) {
893  panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
894  } else {
895  drqBytesLeft -= 2;
896  cmdBytesLeft -= 2;
897 
898  // copy next short into data registers
899  if (drqBytesLeft)
900  memcpy((void *)&cmdReg.data,
901  (void *)&dataBuffer[SectorSize - drqBytesLeft],
902  sizeof(uint16_t));
903  }
904 
905  if (drqBytesLeft == 0) {
906  if (cmdBytesLeft == 0) {
907  // Clear the BSY bit
908  setComplete();
910  } else {
912  // set the BSY_BIT
914  // clear the DRQ_BIT
916 
920  }
921  }
922  }
923  break;
924 
925  case Prepare_Data_Out:
926  if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
927  // clear the BSY bit
928  setComplete();
929 
930  if (!isIENSet()) {
932  intrPost();
933  } else {
935  }
936  } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
937  // clear the BSY bit
939  // set the DRQ bit
941 
942  // clear the data buffer to get it ready for writes
943  memset(dataBuffer, 0, MAX_DMA_SIZE);
944 
945  // reset the drqBytes for this block
947 
948  if (cmdBytesLeft == cmdBytes || isIENSet()) {
950  } else {
952  intrPost();
953  }
954  }
955  break;
956 
958  if (action == ACT_STAT_READ) {
960  intrClear();
961  }
962  break;
963 
964  case Transfer_Data_Out:
965  if (action == ACT_DATA_WRITE_BYTE ||
966  action == ACT_DATA_WRITE_SHORT) {
967 
968  if (action == ACT_DATA_READ_BYTE) {
969  panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
970  } else {
971  // copy the latest short into the data buffer
972  memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
973  (void *)&cmdReg.data,
974  sizeof(uint16_t));
975 
976  drqBytesLeft -= 2;
977  cmdBytesLeft -= 2;
978  }
979 
980  if (drqBytesLeft == 0) {
981  // copy the block to the disk
983 
984  // set the BSY bit
986  // set the seek bit
988  // clear the DRQ bit
990 
992 
996  }
997  }
998  break;
999 
1000  case Prepare_Data_Dma:
1001  if (action == ACT_CMD_ERROR) {
1002  // clear the BSY bit
1003  setComplete();
1004 
1005  if (!isIENSet()) {
1007  intrPost();
1008  } else {
1010  }
1011  } else if (action == ACT_DMA_READY) {
1012  // clear the BSY bit
1013  status &= ~STATUS_BSY_BIT;
1014  // set the DRQ bit
1016 
1018 
1019  if (dmaState != Dma_Idle)
1020  panic("Inconsistent DMA state, should be Dma_Idle\n");
1021 
1022  dmaState = Dma_Start;
1023  // wait for the write to the DMA start bit
1024  }
1025  break;
1026 
1027  case Transfer_Data_Dma:
1028  if (action == ACT_CMD_ERROR) {
1029  dmaAborted = true;
1031  } else if (action == ACT_DMA_DONE) {
1032  // clear the BSY bit
1033  setComplete();
1034  // set the seek bit
1036  // clear the controller state for DMA transfer
1037  ctrl->setDmaComplete(this);
1038 
1039  if (!isIENSet()) {
1041  intrPost();
1042  } else {
1044  }
1045  }
1046  break;
1047 
1048  case Device_Dma_Abort:
1049  if (action == ACT_CMD_ERROR) {
1050  setComplete();
1052  ctrl->setDmaComplete(this);
1053  dmaAborted = false;
1054  dmaState = Dma_Idle;
1055 
1056  if (!isIENSet()) {
1058  intrPost();
1059  } else {
1061  }
1062  } else {
1063  DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
1064  }
1065  break;
1066 
1067  default:
1068  panic("Unknown IDE device state: %#x\n", devState);
1069  }
1070 }
1071 
1072 void
1074 {
1075  // Check all outstanding events to see if they are scheduled
1076  // these are all mutually exclusive
1077  Tick reschedule = 0;
1078  Events_t event = None;
1079 
1080  int eventCount = 0;
1081 
1082  if (dmaTransferEvent.scheduled()) {
1083  reschedule = dmaTransferEvent.when();
1084  event = Transfer;
1085  eventCount++;
1086  }
1087  if (dmaReadWaitEvent.scheduled()) {
1088  reschedule = dmaReadWaitEvent.when();
1089  event = ReadWait;
1090  eventCount++;
1091  }
1092  if (dmaWriteWaitEvent.scheduled()) {
1093  reschedule = dmaWriteWaitEvent.when();
1094  event = WriteWait;
1095  eventCount++;
1096  }
1097  if (dmaPrdReadEvent.scheduled()) {
1098  reschedule = dmaPrdReadEvent.when();
1099  event = PrdRead;
1100  eventCount++;
1101  }
1102  if (dmaReadEvent.scheduled()) {
1103  reschedule = dmaReadEvent.when();
1104  event = DmaRead;
1105  eventCount++;
1106  }
1107  if (dmaWriteEvent.scheduled()) {
1108  reschedule = dmaWriteEvent.when();
1109  event = DmaWrite;
1110  eventCount++;
1111  }
1112 
1113  assert(eventCount <= 1);
1114 
1115  SERIALIZE_SCALAR(reschedule);
1117 
1118  // Serialize device registers
1129 
1130  // Serialize the PRD related information
1135 
1137  // Serialize current transfer related information
1148 }
1149 
1150 void
1152 {
1153  // Reschedule events that were outstanding
1154  // these are all mutually exclusive
1155  Tick reschedule = 0;
1156  Events_t event = None;
1157 
1158  UNSERIALIZE_SCALAR(reschedule);
1160 
1161  switch (event) {
1162  case None : break;
1163  case Transfer : schedule(dmaTransferEvent, reschedule); break;
1164  case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
1165  case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
1166  case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
1167  case DmaRead : schedule(dmaReadEvent, reschedule); break;
1168  case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1169  }
1170 
1171  // Unserialize device registers
1182 
1183  // Unserialize the PRD related information
1188 
1190  // Unserialize current transfer related information
1201 }
1202 
1203 IdeDisk *
1204 IdeDiskParams::create()
1205 {
1206  return new IdeDisk(this);
1207 }
#define DPRINTF(x,...)
Definition: trace.hh:212
#define DATA_OFFSET
Definition: ide_disk.hh:98
bool nIENBit
Interrupt enable bit.
Definition: ide_disk.hh:237
bool next()
Advance generator to next chunk.
#define SECTOR_OFFSET
Definition: ide_disk.hh:102
uint8_t head
Definition: ide_disk.hh:135
uint16_t atap_extensions
Definition: ide_atareg.h:127
#define CONTROL_RST_BIT
Definition: ide_disk.hh:114
void dmaWriteDone()
Definition: ide_disk.cc:552
void dmaPrdReadDone()
Definition: ide_disk.cc:357
void reset(int id)
Reset the device state.
Definition: ide_disk.cc:145
void writeCommand(const Addr offset, int size, const uint8_t *data)
Definition: ide_disk.cc:264
EventWrapper< IdeDisk,&IdeDisk::dmaWriteDone > dmaWriteEvent
Definition: ide_disk.hh:336
~IdeDisk()
Delete the data buffer.
Definition: ide_disk.cc:138
#define MAX_DMA_SIZE
Definition: ide_disk.hh:63
DmaState_t dmaState
Dma state.
Definition: ide_disk.hh:241
void dmaRead(Addr addr, int size, Event *event, uint8_t *data, Tick delay=0)
Definition: dma_device.hh:170
ChunkGenerator * dmaWriteCG
Definition: ide_disk.hh:322
#define WDCC_FLUSHCACHE
Definition: ide_wdcreg.h:100
uint8_t atap_piomode_supp
Definition: ide_atareg.h:145
#define panic(...)
Definition: misc.hh:153
void doDmaRead()
Definition: ide_disk.cc:426
#define LCYL_OFFSET
Definition: ide_disk.hh:103
bool isDiskSelected(IdeDisk *diskPtr)
See if a disk is selected based on its pointer.
Definition: ide_ctrl.cc:139
struct PrdEntry PrdEntry_t
uint32_t curPrdAddr
PRD table base address.
Definition: ide_disk.hh:245
void regStats() override
Register Statistics.
Definition: ide_disk.cc:393
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: ide_disk.cc:1073
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: ide_disk.cc:1151
uint32_t baseAddr
Definition: ide_disk.hh:72
Device model for an IDE disk.
uint8_t atap_capabilities1
Definition: ide_atareg.h:105
void doDmaTransfer()
Definition: ide_disk.cc:336
#define CONTROL_OFFSET
Definition: ide_disk.hh:110
void startCommand()
Definition: ide_disk.cc:625
uint32_t getByteCount()
Definition: ide_disk.hh:86
unsigned size() const
Return size in bytes of current chunk.
#define WDCC_STANDBY_IMMED
Definition: ide_wdcreg.h:108
uint8_t error
Definition: ide_disk.hh:128
PrdEntry_t entry
Definition: ide_disk.hh:79
#define STATUS_OFFSET
Definition: ide_disk.hh:107
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:381
#define ALTSTAT_OFFSET
Definition: ide_disk.hh:111
Stats::Scalar dmaReadTxs
Definition: ide_disk.hh:257
int devID
Device ID (master=0/slave=1)
Definition: ide_disk.hh:249
uint8_t cyl_high
Definition: ide_disk.hh:132
DiskImage * image
The image that contains the data of this disk.
Definition: ide_disk.hh:213
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, Tick delay=0)
Definition: dma_device.hh:164
Simple PCI IDE controller with bus mastering capability and UDMA modeled after controller in the Inte...
Bitfield< 23, 0 > offset
Definition: types.hh:149
#define NSECTOR_OFFSET
Definition: ide_disk.hh:101
#define DRIVE_LBA_BIT
Definition: ide_disk.hh:121
unsigned complete() const
Number of bytes we have already chunked up.
bool dmaAborted
DMA Aborted.
Definition: ide_disk.hh:253
EventWrapper< IdeDisk,&IdeDisk::dmaPrdReadDone > dmaPrdReadEvent
Definition: ide_disk.hh:328
uint16_t atap_hwreset_res
Definition: ide_atareg.h:242
uint32_t drqBytesLeft
Number of bytes left in DRQ block.
Definition: ide_disk.hh:229
virtual void regStats()
Register statistics for this object.
Definition: sim_object.cc:105
void updateState(DevAction_t action)
Definition: ide_disk.cc:773
Stats::Scalar dmaWriteBytes
Definition: ide_disk.hh:259
Addr pciToDma(Addr pci_addr) const
Definition: device.hh:189
#define WDCC_READ
Definition: ide_wdcreg.h:80
EventWrapper< IdeDisk,&IdeDisk::doDmaTransfer > dmaTransferEvent
Definition: ide_disk.hh:310
#define WDCC_WRITEDMA
Definition: ide_wdcreg.h:94
uint8_t atap_curmulti
Definition: ide_atareg.h:136
uint16_t atap_multi
Definition: ide_atareg.h:102
void intrClear()
Definition: ide_disk.cc:755
const char data[]
Definition: circlebuf.cc:43
bool isDEVSelect()
Definition: ide_disk.cc:189
#define DEV0
Definition: ide_disk.hh:123
uint8_t atap_model[40]
Definition: ide_atareg.h:101
#define WDCC_IDENTIFY
Definition: ide_wdcreg.h:101
#define SET_FEATURES
Definition: ide_wdcreg.h:102
void dmaReadDone()
Definition: ide_disk.cc:465
uint8_t command
Definition: ide_disk.hh:137
virtual std::streampos size() const =0
uint8_t atap_curmulti_valid
Definition: ide_atareg.h:137
#define WDC_VER_ATA7
Definition: ide_atareg.h:182
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:145
uint8_t drive
Definition: ide_disk.hh:134
Tick curTick()
The current simulated tick.
Definition: core.hh:47
#define STATUS_SEEK_BIT
Definition: ide_disk.hh:119
#define WDCC_IDLE
Definition: ide_wdcreg.h:104
uint8_t sec_count
Definition: ide_disk.hh:129
uint32_t cmdBytesLeft
Number of bytes left in command data transfer.
Definition: ide_disk.hh:227
#define WDSF_VERIFY
Definition: ide_wdcreg.h:158
void readCommand(const Addr offset, int size, uint8_t *data)
Definition: ide_disk.cc:208
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:397
#define WDCC_RECAL
Definition: ide_wdcreg.h:78
#define WDSF_READ_NATIVE_MAX
Definition: ide_wdcreg.h:156
uint64_t Tick
Tick count type.
Definition: types.hh:63
#define HCYL_OFFSET
Definition: ide_disk.hh:104
enum Events Events_t
uint16_t atap_sectors
Definition: ide_atareg.h:94
Stats::Scalar dmaReadBytes
Definition: ide_disk.hh:256
This class takes an arbitrary memory region (address/length pair) and generates a series of appropria...
void doDmaDataRead()
Definition: ide_disk.cc:381
uint8_t atap_udmamode_supp
Definition: ide_atareg.h:231
#define CONTROL_IEN_BIT
Definition: ide_disk.hh:115
#define COMMAND_OFFSET
Definition: ide_disk.hh:108
virtual std::streampos write(const uint8_t *data, std::streampos offset)=0
uint32_t getLBABase()
Definition: ide_disk.hh:360
#define SERIALIZE_ARRAY(member, size)
Definition: serialize.hh:158
uint16_t byteCount
Definition: ide_disk.hh:73
#define SectorSize
Definition: disk_image.hh:46
struct ataparams driveID
Drive identification structure for this disk.
Definition: ide_disk.hh:221
IdeDisk(const Params *p)
Definition: ide_disk.cc:69
uint16_t atap_ata_major
Definition: ide_atareg.h:175
EventWrapper< IdeDisk,&IdeDisk::doDmaWrite > dmaWriteWaitEvent
Definition: ide_disk.hh:324
#define WDCC_READDMA
Definition: ide_wdcreg.h:93
#define FEATURES_OFFSET
Definition: ide_disk.hh:100
void writeControl(const Addr offset, int size, const uint8_t *data)
Definition: ide_disk.cc:312
void abortDma()
Definition: ide_disk.cc:613
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
uint32_t getBaseAddr()
Definition: ide_disk.hh:81
#define ULL(N)
uint64_t constant
Definition: types.hh:50
#define DMA_BACKOFF_PERIOD
Definition: ide_disk.hh:61
uint32_t curSector
Current sector in access.
Definition: ide_disk.hh:231
Bitfield< 10, 5 > event
uint8_t status
Status register.
Definition: ide_disk.hh:235
uint16_t atap_cylinders
Definition: ide_atareg.h:90
const Addr PageBytes
Definition: isa_traits.hh:52
EventWrapper< IdeDisk,&IdeDisk::doDmaRead > dmaReadWaitEvent
Definition: ide_disk.hh:317
DevState_t devState
Device state.
Definition: ide_disk.hh:239
void doDmaWrite()
Definition: ide_disk.cc:511
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:143
uint16_t data
Definition: ide_disk.hh:127
#define UNSERIALIZE_ENUM(scalar)
Definition: serialize.hh:151
#define UNSERIALIZE_ARRAY(member, size)
Definition: serialize.hh:161
enum DevAction DevAction_t
ChunkGenerator * dmaReadCG
Definition: ide_disk.hh:315
uint16_t endOfTable
Definition: ide_disk.hh:74
Derived & name(const std::string &name)
Set the name and marks this stat to print at the end of simulation.
Definition: statistics.hh:254
uint32_t cmdBytes
Number of bytes in command data transfer.
Definition: ide_disk.hh:225
#define STATUS_BSY_BIT
Definition: ide_disk.hh:116
void reschedule(Event &event, Tick when, bool always=false)
Definition: eventq.hh:740
#define DRIVE_OFFSET
Definition: ide_disk.hh:106
#define WDCC_WRITE
Definition: ide_wdcreg.h:81
PrdTableEntry curPrd
PRD entry.
Definition: ide_disk.hh:247
int size()
Definition: pagetable.hh:146
uint8_t cyl_low
Definition: ide_disk.hh:131
virtual const std::string name() const
Definition: sim_object.hh:117
IDE Disk device model.
Definition: ide_disk.hh:207
CommandReg_t cmdReg
Command block registers.
Definition: ide_disk.hh:233
#define WDCC_READMULTI
Definition: ide_wdcreg.h:89
bool intrPending
Interrupt pending.
Definition: ide_disk.hh:251
std::ostream CheckpointOut
Definition: serialize.hh:67
EventWrapper< IdeDisk,&IdeDisk::dmaReadDone > dmaReadEvent
Definition: ide_disk.hh:332
bool done() const
Are we done? That is, did the last call to next() advance past the end of the region?
IdeDiskParams Params
Definition: ide_disk.hh:263
virtual std::streampos read(uint8_t *data, std::streampos offset) const =0
bool dmaRead
Dma transaction is a read.
Definition: ide_disk.hh:243
Disk Image Interfaces.
bool isIENSet()
Definition: ide_disk.hh:347
#define STATUS_DF_BIT
Definition: ide_disk.hh:120
void startDma(const uint32_t &prdTableBase)
Definition: ide_disk.cc:595
void doDmaDataWrite()
Definition: ide_disk.cc:488
#define WDCC_SETMULTI
Definition: ide_wdcreg.h:91
Addr pciToDma(Addr pciAddr)
Definition: ide_disk.cc:195
#define STATUS_DRQ_BIT
Definition: ide_disk.hh:118
uint8_t sec_num
Definition: ide_disk.hh:130
#define ATAPI_IDENTIFY_DEVICE
Definition: ide_wdcreg.h:171
Stats::Scalar dmaReadFullPages
Definition: ide_disk.hh:255
Addr addr() const
Return starting address of current chunk.
void schedule(Event &event, Tick when)
Definition: eventq.hh:728
#define STATUS_DRDY_BIT
Definition: ide_disk.hh:117
#define ERROR_OFFSET
Definition: ide_disk.hh:99
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:282
IdeController * ctrl
The IDE controller for this disk.
Definition: ide_disk.hh:211
#define WDSF_SEEK
Definition: ide_wdcreg.h:157
void writeDisk(uint32_t sector, uint8_t *data)
Definition: ide_disk.cc:581
#define WDCC_IDP
Definition: ide_wdcreg.h:87
Derived & desc(const std::string &_desc)
Set the description and marks this stat to print at the end of simulation.
Definition: statistics.hh:287
uint8_t * dataBuffer
Data buffer for transfers.
Definition: ide_disk.hh:223
#define MAX_MULTSECT
Definition: ide_disk.hh:65
Declaration and inline definition of ChunkGenerator object.
uint16_t getEOT()
Definition: ide_disk.hh:92
bool dmaPending() const
Definition: dma_device.hh:176
void readControl(const Addr offset, int size, uint8_t *data)
Definition: ide_disk.cc:254
uint32_t atap_capacity
Definition: ide_atareg.h:140
Bitfield< 0 > p
uint8_t atap_dmamode_supp
Definition: ide_atareg.h:143
void readDisk(uint32_t sector, uint8_t *data)
Definition: ide_disk.cc:571
void setComplete()
Definition: ide_disk.hh:350
void setDmaComplete(IdeDisk *disk)
Definition: ide_ctrl.cc:152
void intrPost()
Definition: ide_ctrl.cc:145
Stats::Scalar dmaWriteFullPages
Definition: ide_disk.hh:258
void intrClear()
Definition: device.hh:194
#define DEV1
Definition: ide_disk.hh:124
Abstract superclass for simulation objects.
Definition: sim_object.hh:94
int diskDelay
The disk delay in microseconds.
Definition: ide_disk.hh:217
#define WDCC_WRITEMULTI
Definition: ide_wdcreg.h:90
#define SERIALIZE_ENUM(scalar)
Definition: serialize.hh:149
void intrPost()
Definition: ide_disk.cc:740
uint16_t atap_heads
Definition: ide_atareg.h:92
Stats::Scalar dmaWriteTxs
Definition: ide_disk.hh:260

Generated on Fri Jun 9 2017 13:03:47 for gem5 by doxygen 1.8.6