gem5  v19.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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 "debug/IdeDisk.hh"
61 #include "dev/storage/ide_ctrl.hh"
62 #include "sim/core.hh"
63 #include "sim/sim_object.hh"
64 
66  : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay),
67  dmaTransferEvent([this]{ doDmaTransfer(); }, name()),
68  dmaReadCG(NULL),
69  dmaReadWaitEvent([this]{ doDmaRead(); }, name()),
70  dmaWriteCG(NULL),
71  dmaWriteWaitEvent([this]{ doDmaWrite(); }, name()),
72  dmaPrdReadEvent([this]{ dmaPrdReadDone(); }, name()),
73  dmaReadEvent([this]{ dmaReadDone(); }, name()),
74  dmaWriteEvent([this]{ dmaWriteDone(); }, name())
75 {
76  // Reset the device state
77  reset(p->driveID);
78 
79  // fill out the drive ID structure
80  memset(&driveID, 0, sizeof(struct ataparams));
81 
82  // Calculate LBA and C/H/S values
83  uint16_t cylinders;
84  uint8_t heads;
85  uint8_t sectors;
86 
87  uint32_t lba_size = image->size();
88  if (lba_size >= 16383*16*63) {
89  cylinders = 16383;
90  heads = 16;
91  sectors = 63;
92  } else {
93  if (lba_size >= 63)
94  sectors = 63;
95  else if (lba_size == 0)
96  panic("Bad IDE image size: 0\n");
97  else
98  sectors = lba_size;
99 
100  if ((lba_size / sectors) >= 16)
101  heads = 16;
102  else
103  heads = (lba_size / sectors);
104 
105  cylinders = lba_size / (heads * sectors);
106  }
107 
108  // Setup the model name
109  strncpy((char *)driveID.atap_model, "5MI EDD si k",
110  sizeof(driveID.atap_model));
111  // Set the maximum multisector transfer size
113  // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
115  // UDMA support, EIDE support
116  driveID.atap_extensions = 0x6;
117  // Setup default C/H/S settings
118  driveID.atap_cylinders = cylinders;
119  driveID.atap_sectors = sectors;
120  driveID.atap_heads = heads;
121  // Setup the current multisector transfer size
124  // Number of sectors on disk
125  driveID.atap_capacity = lba_size;
126  // Multiword DMA mode 2 and below supported
128  // Set PIO mode 4 and 3 supported
130  // Set DMA mode 4 and below supported
132  // Statically set hardware config word
133  driveID.atap_hwreset_res = 0x4001;
134 
135  //arbitrary for now...
137 }
138 
140 {
141  // destroy the data buffer
142  delete [] dataBuffer;
143 }
144 
145 void
147 {
148  // initialize the data buffer and shadow registers
149  dataBuffer = new uint8_t[MAX_DMA_SIZE];
150 
151  memset(dataBuffer, 0, MAX_DMA_SIZE);
152  memset(&cmdReg, 0, sizeof(CommandReg_t));
153  memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
154 
155  curPrdAddr = 0;
156  curSector = 0;
157  cmdBytes = 0;
158  cmdBytesLeft = 0;
159  drqBytesLeft = 0;
160  dmaRead = false;
161  intrPending = false;
162  dmaAborted = false;
163 
164  // set the device state to idle
165  dmaState = Dma_Idle;
166 
167  if (id == DEV0) {
169  devID = DEV0;
170  } else if (id == DEV1) {
172  devID = DEV1;
173  } else {
174  panic("Invalid device ID: %#x\n", id);
175  }
176 
177  // set the device ready bit
179 
180  /* The error register must be set to 0x1 on start-up to
181  indicate that no diagnostic error was detected */
182  cmdReg.error = 0x1;
183 }
184 
186 // Utility functions
188 
189 bool
191 {
192  return ctrl->isDiskSelected(this);
193 }
194 
195 Addr
197 {
198  if (ctrl)
199  return ctrl->pciToDma(pciAddr);
200  else
201  panic("Access to unset controller!\n");
202 }
203 
205 // Device registers read/write
207 
208 void
209 IdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
210 {
211  if (offset == DATA_OFFSET) {
212  if (size == sizeof(uint16_t)) {
213  *(uint16_t *)data = cmdReg.data;
214  } else if (size == sizeof(uint32_t)) {
215  *(uint16_t *)data = cmdReg.data;
217  *((uint16_t *)data + 1) = cmdReg.data;
218  } else {
219  panic("Data read of unsupported size %d.\n", size);
220  }
222  return;
223  }
224  assert(size == sizeof(uint8_t));
225  switch (offset) {
226  case ERROR_OFFSET:
227  *data = cmdReg.error;
228  break;
229  case NSECTOR_OFFSET:
230  *data = cmdReg.sec_count;
231  break;
232  case SECTOR_OFFSET:
233  *data = cmdReg.sec_num;
234  break;
235  case LCYL_OFFSET:
236  *data = cmdReg.cyl_low;
237  break;
238  case HCYL_OFFSET:
239  *data = cmdReg.cyl_high;
240  break;
241  case DRIVE_OFFSET:
242  *data = cmdReg.drive;
243  break;
244  case STATUS_OFFSET:
245  *data = status;
247  break;
248  default:
249  panic("Invalid IDE command register offset: %#x\n", offset);
250  }
251  DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
252 }
253 
254 void
255 IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
256 {
257  assert(size == sizeof(uint8_t));
258  *data = status;
259  if (offset != ALTSTAT_OFFSET)
260  panic("Invalid IDE control register offset: %#x\n", offset);
261  DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
262 }
263 
264 void
265 IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
266 {
267  if (offset == DATA_OFFSET) {
268  if (size == sizeof(uint16_t)) {
269  cmdReg.data = *(const uint16_t *)data;
270  } else if (size == sizeof(uint32_t)) {
271  cmdReg.data = *(const uint16_t *)data;
273  cmdReg.data = *((const uint16_t *)data + 1);
274  } else {
275  panic("Data write of unsupported size %d.\n", size);
276  }
278  return;
279  }
280 
281  assert(size == sizeof(uint8_t));
282  switch (offset) {
283  case FEATURES_OFFSET:
284  break;
285  case NSECTOR_OFFSET:
286  cmdReg.sec_count = *data;
287  break;
288  case SECTOR_OFFSET:
289  cmdReg.sec_num = *data;
290  break;
291  case LCYL_OFFSET:
292  cmdReg.cyl_low = *data;
293  break;
294  case HCYL_OFFSET:
295  cmdReg.cyl_high = *data;
296  break;
297  case DRIVE_OFFSET:
298  cmdReg.drive = *data;
300  break;
301  case COMMAND_OFFSET:
302  cmdReg.command = *data;
304  break;
305  default:
306  panic("Invalid IDE command register offset: %#x\n", offset);
307  }
308  DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
309  (uint32_t)*data);
310 }
311 
312 void
313 IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
314 {
315  if (offset != CONTROL_OFFSET)
316  panic("Invalid IDE control register offset: %#x\n", offset);
317 
318  if (*data & CONTROL_RST_BIT) {
319  // force the device into the reset state
322  } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
324  }
325 
326  nIENBit = *data & CONTROL_IEN_BIT;
327 
328  DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
329  (uint32_t)*data);
330 }
331 
333 // Perform DMA transactions
335 
336 void
338 {
339  if (dmaAborted) {
340  DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n");
342  return;
343  }
344 
346  panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
347  dmaState, devState);
348 
351  return;
352  } else
354  (uint8_t*)&curPrd.entry);
355 }
356 
357 void
359 {
360  if (dmaAborted) {
361  DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n");
363  return;
364  }
365 
367  "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
370  curPrd.getEOT(), curSector);
371 
372  // the prd pointer has already been translated, so just do an increment
373  curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
374 
375  if (dmaRead)
376  doDmaDataRead();
377  else
378  doDmaDataWrite();
379 }
380 
381 void
383 {
385  Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
386 
387  DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
388  diskDelay, totalDiskDelay);
389 
390  schedule(dmaReadWaitEvent, curTick() + totalDiskDelay);
391 }
392 
393 void
395 {
397 
398  using namespace Stats;
400  .name(name() + ".dma_read_full_pages")
401  .desc("Number of full page size DMA reads (not PRD).")
402  ;
404  .name(name() + ".dma_read_bytes")
405  .desc("Number of bytes transfered via DMA reads (not PRD).")
406  ;
407  dmaReadTxs
408  .name(name() + ".dma_read_txs")
409  .desc("Number of DMA read transactions (not PRD).")
410  ;
411 
413  .name(name() + ".dma_write_full_pages")
414  .desc("Number of full page size DMA writes.")
415  ;
417  .name(name() + ".dma_write_bytes")
418  .desc("Number of bytes transfered via DMA writes.")
419  ;
421  .name(name() + ".dma_write_txs")
422  .desc("Number of DMA write transactions.")
423  ;
424 }
425 
426 void
428 {
429  if (dmaAborted) {
430  DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
431  if (dmaReadCG)
432  delete dmaReadCG;
433  dmaReadCG = NULL;
435  return;
436  }
437 
438  if (!dmaReadCG) {
439  // clear out the data buffer
440  memset(dataBuffer, 0, MAX_DMA_SIZE);
443 
444  }
447  return;
448  } else if (!dmaReadCG->done()) {
449  assert(dmaReadCG->complete() < MAX_DMA_SIZE);
453  dmaReadTxs++;
454  if (dmaReadCG->size() == pageBytes)
456  dmaReadCG->next();
457  } else {
458  assert(dmaReadCG->done());
459  delete dmaReadCG;
460  dmaReadCG = NULL;
461  dmaReadDone();
462  }
463 }
464 
465 void
467 {
468  uint32_t bytesWritten = 0;
469 
470  // write the data to the disk image
471  for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
472  bytesWritten += SectorSize) {
473 
475  writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
476  }
477 
478  // check for the EOT
479  if (curPrd.getEOT()) {
480  assert(cmdBytesLeft == 0);
481  dmaState = Dma_Idle;
483  } else {
484  doDmaTransfer();
485  }
486 }
487 
488 void
490 {
492  Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
493  uint32_t bytesRead = 0;
494 
495  DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
496  diskDelay, totalDiskDelay);
497 
498  memset(dataBuffer, 0, MAX_DMA_SIZE);
499  assert(cmdBytesLeft <= MAX_DMA_SIZE);
500  while (bytesRead < curPrd.getByteCount()) {
501  readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
502  bytesRead += SectorSize;
504  }
505  DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
506  bytesRead, cmdBytesLeft);
507 
508  schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
509 }
510 
511 void
513 {
514  if (dmaAborted) {
515  DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
516  if (dmaWriteCG)
517  delete dmaWriteCG;
518  dmaWriteCG = NULL;
520  return;
521  }
522  if (!dmaWriteCG) {
523  // clear out the data buffer
526  }
529  DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
530  return;
531  } else if (!dmaWriteCG->done()) {
532  assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
535  DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
538  dmaWriteTxs++;
539  if (dmaWriteCG->size() == pageBytes)
541  dmaWriteCG->next();
542  } else {
543  DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
545  assert(dmaWriteCG->done());
546  delete dmaWriteCG;
547  dmaWriteCG = NULL;
548  dmaWriteDone();
549  }
550 }
551 
552 void
554 {
555  DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
557  // check for the EOT
558  if (curPrd.getEOT()) {
559  assert(cmdBytesLeft == 0);
560  dmaState = Dma_Idle;
562  } else {
563  doDmaTransfer();
564  }
565 }
566 
568 // Disk utility routines
570 
571 void
572 IdeDisk::readDisk(uint32_t sector, uint8_t *data)
573 {
574  uint32_t bytesRead = image->read(data, sector);
575 
576  if (bytesRead != SectorSize)
577  panic("Can't read from %s. Only %d of %d read. errno=%d\n",
578  name(), bytesRead, SectorSize, errno);
579 }
580 
581 void
582 IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
583 {
584  uint32_t bytesWritten = image->write(data, sector);
585 
586  if (bytesWritten != SectorSize)
587  panic("Can't write to %s. Only %d of %d written. errno=%d\n",
588  name(), bytesWritten, SectorSize, errno);
589 }
590 
592 // Setup and handle commands
594 
595 void
596 IdeDisk::startDma(const uint32_t &prdTableBase)
597 {
598  if (dmaState != Dma_Start)
599  panic("Inconsistent DMA state, should be in Dma_Start!\n");
600 
602  panic("Inconsistent device state for DMA start!\n");
603 
604  // PRD base address is given by bits 31:2
605  curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
606 
608 
609  // schedule dma transfer (doDmaTransfer)
611 }
612 
613 void
615 {
616  if (dmaState == Dma_Idle)
617  panic("Inconsistent DMA state, should be Start or Transfer!");
618 
620  panic("Inconsistent device state, should be Transfer or Prepare!\n");
621 
623 }
624 
625 void
627 {
628  DevAction_t action = ACT_NONE;
629  uint32_t size = 0;
630  dmaRead = false;
631 
632  // Decode commands
633  switch (cmdReg.command) {
634  // Supported non-data commands
636  size = (uint32_t)image->size() - 1;
637  cmdReg.sec_num = (size & 0xff);
638  cmdReg.cyl_low = ((size & 0xff00) >> 8);
639  cmdReg.cyl_high = ((size & 0xff0000) >> 16);
640  cmdReg.head = ((size & 0xf000000) >> 24);
641 
643  action = ACT_CMD_COMPLETE;
644  break;
645 
646  case WDCC_RECAL:
647  case WDCC_IDP:
648  case WDCC_STANDBY_IMMED:
649  case WDCC_FLUSHCACHE:
650  case WDSF_VERIFY:
651  case WDSF_SEEK:
652  case SET_FEATURES:
653  case WDCC_SETMULTI:
654  case WDCC_IDLE:
656  action = ACT_CMD_COMPLETE;
657  break;
658 
659  // Supported PIO data-in commands
660  case WDCC_IDENTIFY:
662  cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
664  action = ACT_DATA_READY;
665  break;
666 
667  case WDCC_READMULTI:
668  case WDCC_READ:
669  if (!(cmdReg.drive & DRIVE_LBA_BIT))
670  panic("Attempt to perform CHS access, only supports LBA\n");
671 
672  if (cmdReg.sec_count == 0)
673  cmdBytes = cmdBytesLeft = (256 * SectorSize);
674  else
676 
677  curSector = getLBABase();
678 
681  action = ACT_DATA_READY;
682  break;
683 
684  // Supported PIO data-out commands
685  case WDCC_WRITEMULTI:
686  case WDCC_WRITE:
687  if (!(cmdReg.drive & DRIVE_LBA_BIT))
688  panic("Attempt to perform CHS access, only supports LBA\n");
689 
690  if (cmdReg.sec_count == 0)
691  cmdBytes = cmdBytesLeft = (256 * SectorSize);
692  else
694  DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
695  curSector = getLBABase();
696 
698  action = ACT_DATA_READY;
699  break;
700 
701  // Supported DMA commands
702  case WDCC_WRITEDMA:
703  dmaRead = true; // a write to the disk is a DMA read from memory
705  case WDCC_READDMA:
706  if (!(cmdReg.drive & DRIVE_LBA_BIT))
707  panic("Attempt to perform CHS access, only supports LBA\n");
708 
709  if (cmdReg.sec_count == 0)
710  cmdBytes = cmdBytesLeft = (256 * SectorSize);
711  else
713  DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
714 
715  curSector = getLBABase();
716 
718  action = ACT_DMA_READY;
719  break;
720 
721  default:
722  panic("Unsupported ATA command: %#x\n", cmdReg.command);
723  }
724 
725  if (action != ACT_NONE) {
726  // set the BSY bit
728  // clear the DRQ bit
730  // clear the DF bit
731  status &= ~STATUS_DF_BIT;
732 
733  updateState(action);
734  }
735 }
736 
738 // Handle setting and clearing interrupts
740 
741 void
743 {
744  DPRINTF(IdeDisk, "Posting Interrupt\n");
745  if (intrPending)
746  panic("Attempt to post an interrupt with one pending\n");
747 
748  intrPending = true;
749 
750  // talk to controller to set interrupt
751  if (ctrl) {
752  ctrl->intrPost();
753  }
754 }
755 
756 void
758 {
759  DPRINTF(IdeDisk, "Clearing Interrupt\n");
760  if (!intrPending)
761  panic("Attempt to clear a non-pending interrupt\n");
762 
763  intrPending = false;
764 
765  // talk to controller to clear interrupt
766  if (ctrl)
767  ctrl->intrClear();
768 }
769 
771 // Manage the device internal state machine
773 
774 void
776 {
777  switch (devState) {
778  case Device_Srst:
779  if (action == ACT_SRST_SET) {
780  // set the BSY bit
782  } else if (action == ACT_SRST_CLEAR) {
783  // clear the BSY bit
785 
786  // reset the device state
787  reset(devID);
788  }
789  break;
790 
791  case Device_Idle_S:
792  if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
794  } else if (action == ACT_CMD_WRITE) {
795  startCommand();
796  }
797 
798  break;
799 
800  case Device_Idle_SI:
801  if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
803  intrClear();
804  } else if (action == ACT_STAT_READ || isIENSet()) {
806  intrClear();
807  } else if (action == ACT_CMD_WRITE) {
808  intrClear();
809  startCommand();
810  }
811 
812  break;
813 
814  case Device_Idle_NS:
815  if (action == ACT_SELECT_WRITE && isDEVSelect()) {
816  if (!isIENSet() && intrPending) {
818  intrPost();
819  }
820  if (isIENSet() || !intrPending) {
822  }
823  }
824  break;
825 
826  case Command_Execution:
827  if (action == ACT_CMD_COMPLETE) {
828  // clear the BSY bit
829  setComplete();
830 
831  if (!isIENSet()) {
833  intrPost();
834  } else {
836  }
837  }
838  break;
839 
840  case Prepare_Data_In:
841  if (action == ACT_CMD_ERROR) {
842  // clear the BSY bit
843  setComplete();
844 
845  if (!isIENSet()) {
847  intrPost();
848  } else {
850  }
851  } else if (action == ACT_DATA_READY) {
852  // clear the BSY bit
854  // set the DRQ bit
856 
857  // copy the data into the data buffer
858  if (cmdReg.command == WDCC_IDENTIFY ||
860  // Reset the drqBytes for this block
861  drqBytesLeft = sizeof(struct ataparams);
862 
863  memcpy((void *)dataBuffer, (void *)&driveID,
864  sizeof(struct ataparams));
865  } else {
866  // Reset the drqBytes for this block
868 
870  }
871 
872  // put the first two bytes into the data register
873  memcpy((void *)&cmdReg.data, (void *)dataBuffer,
874  sizeof(uint16_t));
875 
876  if (!isIENSet()) {
878  intrPost();
879  } else {
881  }
882  }
883  break;
884 
885  case Data_Ready_INTRQ_In:
886  if (action == ACT_STAT_READ) {
888  intrClear();
889  }
890  break;
891 
892  case Transfer_Data_In:
893  if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
894  if (action == ACT_DATA_READ_BYTE) {
895  panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
896  } else {
897  drqBytesLeft -= 2;
898  cmdBytesLeft -= 2;
899 
900  // copy next short into data registers
901  if (drqBytesLeft)
902  memcpy((void *)&cmdReg.data,
903  (void *)&dataBuffer[SectorSize - drqBytesLeft],
904  sizeof(uint16_t));
905  }
906 
907  if (drqBytesLeft == 0) {
908  if (cmdBytesLeft == 0) {
909  // Clear the BSY bit
910  setComplete();
912  } else {
914  // set the BSY_BIT
916  // clear the DRQ_BIT
918 
922  }
923  }
924  }
925  break;
926 
927  case Prepare_Data_Out:
928  if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
929  // clear the BSY bit
930  setComplete();
931 
932  if (!isIENSet()) {
934  intrPost();
935  } else {
937  }
938  } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
939  // clear the BSY bit
941  // set the DRQ bit
943 
944  // clear the data buffer to get it ready for writes
945  memset(dataBuffer, 0, MAX_DMA_SIZE);
946 
947  // reset the drqBytes for this block
949 
950  if (cmdBytesLeft == cmdBytes || isIENSet()) {
952  } else {
954  intrPost();
955  }
956  }
957  break;
958 
960  if (action == ACT_STAT_READ) {
962  intrClear();
963  }
964  break;
965 
966  case Transfer_Data_Out:
967  if (action == ACT_DATA_WRITE_BYTE ||
968  action == ACT_DATA_WRITE_SHORT) {
969 
970  if (action == ACT_DATA_READ_BYTE) {
971  panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
972  } else {
973  // copy the latest short into the data buffer
974  memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
975  (void *)&cmdReg.data,
976  sizeof(uint16_t));
977 
978  drqBytesLeft -= 2;
979  cmdBytesLeft -= 2;
980  }
981 
982  if (drqBytesLeft == 0) {
983  // copy the block to the disk
985 
986  // set the BSY bit
988  // set the seek bit
990  // clear the DRQ bit
992 
994 
998  }
999  }
1000  break;
1001 
1002  case Prepare_Data_Dma:
1003  if (action == ACT_CMD_ERROR) {
1004  // clear the BSY bit
1005  setComplete();
1006 
1007  if (!isIENSet()) {
1009  intrPost();
1010  } else {
1012  }
1013  } else if (action == ACT_DMA_READY) {
1014  // clear the BSY bit
1015  status &= ~STATUS_BSY_BIT;
1016  // set the DRQ bit
1018 
1020 
1021  if (dmaState != Dma_Idle)
1022  panic("Inconsistent DMA state, should be Dma_Idle\n");
1023 
1024  dmaState = Dma_Start;
1025  // wait for the write to the DMA start bit
1026  }
1027  break;
1028 
1029  case Transfer_Data_Dma:
1030  if (action == ACT_CMD_ERROR) {
1031  dmaAborted = true;
1033  } else if (action == ACT_DMA_DONE) {
1034  // clear the BSY bit
1035  setComplete();
1036  // set the seek bit
1038  // clear the controller state for DMA transfer
1039  ctrl->setDmaComplete(this);
1040 
1041  if (!isIENSet()) {
1043  intrPost();
1044  } else {
1046  }
1047  }
1048  break;
1049 
1050  case Device_Dma_Abort:
1051  if (action == ACT_CMD_ERROR) {
1052  setComplete();
1054  ctrl->setDmaComplete(this);
1055  dmaAborted = false;
1056  dmaState = Dma_Idle;
1057 
1058  if (!isIENSet()) {
1060  intrPost();
1061  } else {
1063  }
1064  } else {
1065  DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
1066  }
1067  break;
1068 
1069  default:
1070  panic("Unknown IDE device state: %#x\n", devState);
1071  }
1072 }
1073 
1074 void
1076 {
1077  // Check all outstanding events to see if they are scheduled
1078  // these are all mutually exclusive
1079  Tick reschedule = 0;
1080  Events_t event = None;
1081 
1082  int eventCount = 0;
1083 
1084  if (dmaTransferEvent.scheduled()) {
1085  reschedule = dmaTransferEvent.when();
1086  event = Transfer;
1087  eventCount++;
1088  }
1089  if (dmaReadWaitEvent.scheduled()) {
1090  reschedule = dmaReadWaitEvent.when();
1091  event = ReadWait;
1092  eventCount++;
1093  }
1094  if (dmaWriteWaitEvent.scheduled()) {
1095  reschedule = dmaWriteWaitEvent.when();
1096  event = WriteWait;
1097  eventCount++;
1098  }
1099  if (dmaPrdReadEvent.scheduled()) {
1100  reschedule = dmaPrdReadEvent.when();
1101  event = PrdRead;
1102  eventCount++;
1103  }
1104  if (dmaReadEvent.scheduled()) {
1105  reschedule = dmaReadEvent.when();
1106  event = DmaRead;
1107  eventCount++;
1108  }
1109  if (dmaWriteEvent.scheduled()) {
1110  reschedule = dmaWriteEvent.when();
1111  event = DmaWrite;
1112  eventCount++;
1113  }
1114 
1115  assert(eventCount <= 1);
1116 
1117  SERIALIZE_SCALAR(reschedule);
1119 
1120  // Serialize device registers
1131 
1132  // Serialize the PRD related information
1137 
1139  // Serialize current transfer related information
1150 }
1151 
1152 void
1154 {
1155  // Reschedule events that were outstanding
1156  // these are all mutually exclusive
1157  Tick reschedule = 0;
1158  Events_t event = None;
1159 
1160  UNSERIALIZE_SCALAR(reschedule);
1162 
1163  switch (event) {
1164  case None : break;
1165  case Transfer : schedule(dmaTransferEvent, reschedule); break;
1166  case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
1167  case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
1168  case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
1169  case DmaRead : schedule(dmaReadEvent, reschedule); break;
1170  case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1171  }
1172 
1173  // Unserialize device registers
1184 
1185  // Unserialize the PRD related information
1190 
1192  // Unserialize current transfer related information
1203 }
1204 
1205 IdeDisk *
1206 IdeDiskParams::create()
1207 {
1208  return new IdeDisk(this);
1209 }
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:167
#define DPRINTF(x,...)
Definition: trace.hh:229
#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:553
void dmaPrdReadDone()
Definition: ide_disk.cc:358
void reset(int id)
Reset the device state.
Definition: ide_disk.cc:146
void writeCommand(const Addr offset, int size, const uint8_t *data)
Definition: ide_disk.cc:265
~IdeDisk()
Delete the data buffer.
Definition: ide_disk.cc:139
#define MAX_DMA_SIZE
Definition: ide_disk.hh:63
DmaState_t dmaState
Dma state.
Definition: ide_disk.hh:241
Addr pciToDma(Addr pci_addr) const
Definition: device.hh:198
ChunkGenerator * dmaWriteCG
Definition: ide_disk.hh:325
EventFunctionWrapper dmaReadEvent
Definition: ide_disk.hh:332
#define WDCC_FLUSHCACHE
Definition: ide_wdcreg.h:100
uint8_t atap_piomode_supp
Definition: ide_atareg.h:145
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:401
void doDmaRead()
Definition: ide_disk.cc:427
#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:147
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay=0)
Definition: dma_device.hh:179
struct PrdEntry PrdEntry_t
uint32_t curPrdAddr
PRD table base address.
Definition: ide_disk.hh:247
void regStats() override
Register Statistics.
Definition: ide_disk.cc:394
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: ide_disk.cc:1075
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: ide_disk.cc:1153
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:337
#define CONTROL_OFFSET
Definition: ide_disk.hh:110
void startCommand()
Definition: ide_disk.cc:626
uint32_t getByteCount()
Definition: ide_disk.hh:86
#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
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:282
#define ALTSTAT_OFFSET
Definition: ide_disk.hh:111
Stats::Scalar dmaReadTxs
Definition: ide_disk.hh:259
int devID
Device ID (master=0/slave=1)
Definition: ide_disk.hh:251
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
virtual void regStats()
Callback to set stat parameters.
Definition: group.cc:66
Simple PCI IDE controller with bus mastering capability and UDMA modeled after controller in the Inte...
Bitfield< 23, 0 > offset
Definition: types.hh:154
#define NSECTOR_OFFSET
Definition: ide_disk.hh:101
#define DRIVE_LBA_BIT
Definition: ide_disk.hh:121
bool dmaAborted
DMA Aborted.
Definition: ide_disk.hh:255
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
Definition: cprintf.cc:42
void updateState(DevAction_t action)
Definition: ide_disk.cc:775
Stats::Scalar dmaWriteBytes
Definition: ide_disk.hh:261
#define WDCC_READ
Definition: ide_wdcreg.h:80
#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:757
bool isDEVSelect()
Definition: ide_disk.cc:190
#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:466
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:645
unsigned size() const
Return size in bytes of current chunk.
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
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:385
#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 M5_FALLTHROUGH
Definition: compiler.hh:86
#define WDSF_VERIFY
Definition: ide_wdcreg.h:158
void readCommand(const Addr offset, int size, uint8_t *data)
Definition: ide_disk.cc:209
#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
void dmaRead(Addr addr, int size, Event *event, uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay=0)
Definition: dma_device.hh:192
#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:258
This class takes an arbitrary memory region (address/length pair) and generates a series of appropria...
void doDmaDataRead()
Definition: ide_disk.cc:382
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:359
#define SERIALIZE_ARRAY(member, size)
Definition: serialize.hh:658
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:65
uint16_t atap_ata_major
Definition: ide_atareg.h:175
EventFunctionWrapper dmaWriteEvent
Definition: ide_disk.hh:335
#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:313
void abortDma()
Definition: ide_disk.cc:614
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
virtual const std::string name() const
Definition: sim_object.hh:120
#define DMA_BACKOFF_PERIOD
Definition: ide_disk.hh:61
bool done() const
Are we done? That is, did the last call to next() advance past the end of the region?
uint32_t curSector
Current sector in access.
Definition: ide_disk.hh:231
bool dmaPending() const
Definition: dma_device.hh:205
Bitfield< 10, 5 > event
Addr pageBytes
Size of OS pages.
Definition: ide_disk.hh:245
uint8_t status
Status register.
Definition: ide_disk.hh:235
uint16_t atap_cylinders
Definition: ide_atareg.h:90
EventFunctionWrapper dmaPrdReadEvent
Definition: ide_disk.hh:329
DevState_t devState
Device state.
Definition: ide_disk.hh:239
void doDmaWrite()
Definition: ide_disk.cc:512
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:643
EventFunctionWrapper dmaWriteWaitEvent
Definition: ide_disk.hh:326
uint16_t data
Definition: ide_disk.hh:127
#define UNSERIALIZE_ENUM(scalar)
Definition: serialize.hh:651
#define UNSERIALIZE_ARRAY(member, size)
Definition: serialize.hh:661
enum DevAction DevAction_t
ChunkGenerator * dmaReadCG
Definition: ide_disk.hh:319
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:279
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:756
#define DRIVE_OFFSET
Definition: ide_disk.hh:106
#define WDCC_WRITE
Definition: ide_wdcreg.h:81
PrdTableEntry curPrd
PRD entry.
Definition: ide_disk.hh:249
uint8_t cyl_low
Definition: ide_disk.hh:131
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:253
std::ostream CheckpointOut
Definition: serialize.hh:68
unsigned complete() const
Number of bytes we have already chunked up.
EventFunctionWrapper dmaReadWaitEvent
Definition: ide_disk.hh:320
IdeDiskParams Params
Definition: ide_disk.hh:265
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:346
#define STATUS_DF_BIT
Definition: ide_disk.hh:120
void startDma(const uint32_t &prdTableBase)
Definition: ide_disk.cc:596
void doDmaDataWrite()
Definition: ide_disk.cc:489
#define WDCC_SETMULTI
Definition: ide_wdcreg.h:91
Addr pciToDma(Addr pciAddr)
Definition: ide_disk.cc:196
#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:257
void schedule(Event &event, Tick when)
Definition: eventq.hh:744
#define STATUS_DRDY_BIT
Definition: ide_disk.hh:117
#define ERROR_OFFSET
Definition: ide_disk.hh:99
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:582
#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:312
EventFunctionWrapper dmaTransferEvent
Definition: ide_disk.hh:314
uint8_t * dataBuffer
Data buffer for transfers.
Definition: ide_disk.hh:223
Addr addr() const
Return starting address of current chunk.
#define MAX_MULTSECT
Definition: ide_disk.hh:65
Declaration and inline definition of ChunkGenerator object.
uint16_t getEOT()
Definition: ide_disk.hh:92
void readControl(const Addr offset, int size, uint8_t *data)
Definition: ide_disk.cc:255
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:572
const char data[]
void setComplete()
Definition: ide_disk.hh:349
void setDmaComplete(IdeDisk *disk)
Definition: ide_ctrl.cc:160
void intrPost()
Definition: ide_ctrl.cc:153
Stats::Scalar dmaWriteFullPages
Definition: ide_disk.hh:260
void intrClear()
Definition: device.hh:203
#define DEV1
Definition: ide_disk.hh:124
Abstract superclass for simulation objects.
Definition: sim_object.hh:96
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:649
void intrPost()
Definition: ide_disk.cc:742
uint16_t atap_heads
Definition: ide_atareg.h:92
Stats::Scalar dmaWriteTxs
Definition: ide_disk.hh:262

Generated on Fri Feb 28 2020 16:27:01 for gem5 by doxygen 1.8.13