gem5  v20.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 
45 #include "dev/storage/ide_disk.hh"
46 
47 #include <cerrno>
48 #include <cstring>
49 #include <deque>
50 #include <string>
51 
52 #include "arch/isa_traits.hh"
53 #include "base/chunk_generator.hh"
54 #include "base/cprintf.hh" // csprintf
55 #include "base/trace.hh"
56 #include "debug/IdeDisk.hh"
58 #include "dev/storage/ide_ctrl.hh"
59 #include "sim/core.hh"
60 #include "sim/sim_object.hh"
61 
63  : SimObject(p), ctrl(NULL), image(p->image), diskDelay(p->delay),
64  dmaTransferEvent([this]{ doDmaTransfer(); }, name()),
65  dmaReadCG(NULL),
66  dmaReadWaitEvent([this]{ doDmaRead(); }, name()),
67  dmaWriteCG(NULL),
68  dmaWriteWaitEvent([this]{ doDmaWrite(); }, name()),
69  dmaPrdReadEvent([this]{ dmaPrdReadDone(); }, name()),
70  dmaReadEvent([this]{ dmaReadDone(); }, name()),
71  dmaWriteEvent([this]{ dmaWriteDone(); }, name())
72 {
73  // Reset the device state
74  reset(p->driveID);
75 
76  // fill out the drive ID structure
77  memset(&driveID, 0, sizeof(struct ataparams));
78 
79  // Calculate LBA and C/H/S values
80  uint16_t cylinders;
81  uint8_t heads;
82  uint8_t sectors;
83 
84  uint32_t lba_size = image->size();
85  if (lba_size >= 16383*16*63) {
86  cylinders = 16383;
87  heads = 16;
88  sectors = 63;
89  } else {
90  if (lba_size >= 63)
91  sectors = 63;
92  else if (lba_size == 0)
93  panic("Bad IDE image size: 0\n");
94  else
95  sectors = lba_size;
96 
97  if ((lba_size / sectors) >= 16)
98  heads = 16;
99  else
100  heads = (lba_size / sectors);
101 
102  cylinders = lba_size / (heads * sectors);
103  }
104 
105  // Setup the model name
106  strncpy((char *)driveID.atap_model, "5MI EDD si k",
107  sizeof(driveID.atap_model));
108  // Set the maximum multisector transfer size
110  // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
112  // UDMA support, EIDE support
113  driveID.atap_extensions = 0x6;
114  // Setup default C/H/S settings
115  driveID.atap_cylinders = cylinders;
116  driveID.atap_sectors = sectors;
117  driveID.atap_heads = heads;
118  // Setup the current multisector transfer size
121  // Number of sectors on disk
122  driveID.atap_capacity = lba_size;
123  // Multiword DMA mode 2 and below supported
125  // Set PIO mode 4 and 3 supported
127  // Set DMA mode 4 and below supported
129  // Statically set hardware config word
130  driveID.atap_hwreset_res = 0x4001;
131 
132  //arbitrary for now...
134 }
135 
137 {
138  // destroy the data buffer
139  delete [] dataBuffer;
140 }
141 
142 void
144 {
145  // initialize the data buffer and shadow registers
146  dataBuffer = new uint8_t[MAX_DMA_SIZE];
147 
148  memset(dataBuffer, 0, MAX_DMA_SIZE);
149  memset(&cmdReg, 0, sizeof(CommandReg_t));
150  memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
151 
152  curPrdAddr = 0;
153  curSector = 0;
154  cmdBytes = 0;
155  cmdBytesLeft = 0;
156  drqBytesLeft = 0;
157  dmaRead = false;
158  intrPending = false;
159  dmaAborted = false;
160 
161  // set the device state to idle
162  dmaState = Dma_Idle;
163 
164  if (id == DEV0) {
166  devID = DEV0;
167  } else if (id == DEV1) {
169  devID = DEV1;
170  } else {
171  panic("Invalid device ID: %#x\n", id);
172  }
173 
174  // set the device ready bit
176 
177  /* The error register must be set to 0x1 on start-up to
178  indicate that no diagnostic error was detected */
179  cmdReg.error = 0x1;
180 }
181 
183 // Utility functions
185 
186 bool
188 {
189  return ctrl->isDiskSelected(this);
190 }
191 
192 Addr
194 {
195  if (ctrl)
196  return ctrl->pciToDma(pciAddr);
197  else
198  panic("Access to unset controller!\n");
199 }
200 
202 // Device registers read/write
204 
205 void
206 IdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
207 {
208  if (offset == DATA_OFFSET) {
209  if (size == sizeof(uint16_t)) {
210  *(uint16_t *)data = cmdReg.data;
211  } else if (size == sizeof(uint32_t)) {
212  *(uint16_t *)data = cmdReg.data;
214  *((uint16_t *)data + 1) = cmdReg.data;
215  } else {
216  panic("Data read of unsupported size %d.\n", size);
217  }
219  return;
220  }
221  assert(size == sizeof(uint8_t));
222  switch (offset) {
223  case ERROR_OFFSET:
224  *data = cmdReg.error;
225  break;
226  case NSECTOR_OFFSET:
227  *data = cmdReg.sec_count;
228  break;
229  case SECTOR_OFFSET:
230  *data = cmdReg.sec_num;
231  break;
232  case LCYL_OFFSET:
233  *data = cmdReg.cyl_low;
234  break;
235  case HCYL_OFFSET:
236  *data = cmdReg.cyl_high;
237  break;
238  case DRIVE_OFFSET:
239  *data = cmdReg.drive;
240  break;
241  case STATUS_OFFSET:
242  *data = status;
244  break;
245  default:
246  panic("Invalid IDE command register offset: %#x\n", offset);
247  }
248  DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
249 }
250 
251 void
252 IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
253 {
254  assert(size == sizeof(uint8_t));
255  *data = status;
256  if (offset != ALTSTAT_OFFSET)
257  panic("Invalid IDE control register offset: %#x\n", offset);
258  DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
259 }
260 
261 void
262 IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
263 {
264  if (offset == DATA_OFFSET) {
265  if (size == sizeof(uint16_t)) {
266  cmdReg.data = *(const uint16_t *)data;
267  } else if (size == sizeof(uint32_t)) {
268  cmdReg.data = *(const uint16_t *)data;
270  cmdReg.data = *((const uint16_t *)data + 1);
271  } else {
272  panic("Data write of unsupported size %d.\n", size);
273  }
275  return;
276  }
277 
278  assert(size == sizeof(uint8_t));
279  switch (offset) {
280  case FEATURES_OFFSET:
281  break;
282  case NSECTOR_OFFSET:
283  cmdReg.sec_count = *data;
284  break;
285  case SECTOR_OFFSET:
286  cmdReg.sec_num = *data;
287  break;
288  case LCYL_OFFSET:
289  cmdReg.cyl_low = *data;
290  break;
291  case HCYL_OFFSET:
292  cmdReg.cyl_high = *data;
293  break;
294  case DRIVE_OFFSET:
295  cmdReg.drive = *data;
297  break;
298  case COMMAND_OFFSET:
299  cmdReg.command = *data;
301  break;
302  default:
303  panic("Invalid IDE command register offset: %#x\n", offset);
304  }
305  DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
306  (uint32_t)*data);
307 }
308 
309 void
310 IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
311 {
312  if (offset != CONTROL_OFFSET)
313  panic("Invalid IDE control register offset: %#x\n", offset);
314 
315  if (*data & CONTROL_RST_BIT) {
316  // force the device into the reset state
319  } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
321  }
322 
323  nIENBit = *data & CONTROL_IEN_BIT;
324 
325  DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
326  (uint32_t)*data);
327 }
328 
330 // Perform DMA transactions
332 
333 void
335 {
336  if (dmaAborted) {
337  DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n");
339  return;
340  }
341 
343  panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
344  dmaState, devState);
345 
348  return;
349  } else
351  (uint8_t*)&curPrd.entry);
352 }
353 
354 void
356 {
357  if (dmaAborted) {
358  DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n");
360  return;
361  }
362 
364  "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
367  curPrd.getEOT(), curSector);
368 
369  // the prd pointer has already been translated, so just do an increment
370  curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
371 
372  if (dmaRead)
373  doDmaDataRead();
374  else
375  doDmaDataWrite();
376 }
377 
378 void
380 {
382  Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
383 
384  DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
385  diskDelay, totalDiskDelay);
386 
387  schedule(dmaReadWaitEvent, curTick() + totalDiskDelay);
388 }
389 
390 void
392 {
394 
395  using namespace Stats;
397  .name(name() + ".dma_read_full_pages")
398  .desc("Number of full page size DMA reads (not PRD).")
399  ;
401  .name(name() + ".dma_read_bytes")
402  .desc("Number of bytes transfered via DMA reads (not PRD).")
403  ;
404  dmaReadTxs
405  .name(name() + ".dma_read_txs")
406  .desc("Number of DMA read transactions (not PRD).")
407  ;
408 
410  .name(name() + ".dma_write_full_pages")
411  .desc("Number of full page size DMA writes.")
412  ;
414  .name(name() + ".dma_write_bytes")
415  .desc("Number of bytes transfered via DMA writes.")
416  ;
418  .name(name() + ".dma_write_txs")
419  .desc("Number of DMA write transactions.")
420  ;
421 }
422 
423 void
425 {
426  if (dmaAborted) {
427  DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
428  if (dmaReadCG)
429  delete dmaReadCG;
430  dmaReadCG = NULL;
432  return;
433  }
434 
435  if (!dmaReadCG) {
436  // clear out the data buffer
437  memset(dataBuffer, 0, MAX_DMA_SIZE);
440 
441  }
444  return;
445  } else if (!dmaReadCG->done()) {
446  assert(dmaReadCG->complete() < MAX_DMA_SIZE);
450  dmaReadTxs++;
451  if (dmaReadCG->size() == pageBytes)
453  dmaReadCG->next();
454  } else {
455  assert(dmaReadCG->done());
456  delete dmaReadCG;
457  dmaReadCG = NULL;
458  dmaReadDone();
459  }
460 }
461 
462 void
464 {
465  uint32_t bytesWritten = 0;
466 
467  // write the data to the disk image
468  for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
469  bytesWritten += SectorSize) {
470 
472  writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
473  }
474 
475  // check for the EOT
476  if (curPrd.getEOT()) {
477  assert(cmdBytesLeft == 0);
478  dmaState = Dma_Idle;
480  } else {
481  doDmaTransfer();
482  }
483 }
484 
485 void
487 {
489  Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
490  uint32_t bytesRead = 0;
491 
492  DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
493  diskDelay, totalDiskDelay);
494 
495  memset(dataBuffer, 0, MAX_DMA_SIZE);
496  assert(cmdBytesLeft <= MAX_DMA_SIZE);
497  while (bytesRead < curPrd.getByteCount()) {
498  readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
499  bytesRead += SectorSize;
501  }
502  DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
503  bytesRead, cmdBytesLeft);
504 
505  schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
506 }
507 
508 void
510 {
511  if (dmaAborted) {
512  DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
513  if (dmaWriteCG)
514  delete dmaWriteCG;
515  dmaWriteCG = NULL;
517  return;
518  }
519  if (!dmaWriteCG) {
520  // clear out the data buffer
523  }
526  DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
527  return;
528  } else if (!dmaWriteCG->done()) {
529  assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
532  DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
535  dmaWriteTxs++;
536  if (dmaWriteCG->size() == pageBytes)
538  dmaWriteCG->next();
539  } else {
540  DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
542  assert(dmaWriteCG->done());
543  delete dmaWriteCG;
544  dmaWriteCG = NULL;
545  dmaWriteDone();
546  }
547 }
548 
549 void
551 {
552  DPRINTF(IdeDisk, "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
554  // check for the EOT
555  if (curPrd.getEOT()) {
556  assert(cmdBytesLeft == 0);
557  dmaState = Dma_Idle;
559  } else {
560  doDmaTransfer();
561  }
562 }
563 
565 // Disk utility routines
567 
568 void
569 IdeDisk::readDisk(uint32_t sector, uint8_t *data)
570 {
571  uint32_t bytesRead = image->read(data, sector);
572 
573  if (bytesRead != SectorSize)
574  panic("Can't read from %s. Only %d of %d read. errno=%d\n",
575  name(), bytesRead, SectorSize, errno);
576 }
577 
578 void
579 IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
580 {
581  uint32_t bytesWritten = image->write(data, sector);
582 
583  if (bytesWritten != SectorSize)
584  panic("Can't write to %s. Only %d of %d written. errno=%d\n",
585  name(), bytesWritten, SectorSize, errno);
586 }
587 
589 // Setup and handle commands
591 
592 void
593 IdeDisk::startDma(const uint32_t &prdTableBase)
594 {
595  if (dmaState != Dma_Start)
596  panic("Inconsistent DMA state, should be in Dma_Start!\n");
597 
599  panic("Inconsistent device state for DMA start!\n");
600 
601  // PRD base address is given by bits 31:2
602  curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
603 
605 
606  // schedule dma transfer (doDmaTransfer)
608 }
609 
610 void
612 {
613  if (dmaState == Dma_Idle)
614  panic("Inconsistent DMA state, should be Start or Transfer!");
615 
617  panic("Inconsistent device state, should be Transfer or Prepare!\n");
618 
620 }
621 
622 void
624 {
625  DevAction_t action = ACT_NONE;
626  uint32_t size = 0;
627  dmaRead = false;
628 
629  // Decode commands
630  switch (cmdReg.command) {
631  // Supported non-data commands
633  size = (uint32_t)image->size() - 1;
634  cmdReg.sec_num = (size & 0xff);
635  cmdReg.cyl_low = ((size & 0xff00) >> 8);
636  cmdReg.cyl_high = ((size & 0xff0000) >> 16);
637  cmdReg.head = ((size & 0xf000000) >> 24);
638 
640  action = ACT_CMD_COMPLETE;
641  break;
642 
643  case WDCC_RECAL:
644  case WDCC_IDP:
645  case WDCC_STANDBY_IMMED:
646  case WDCC_FLUSHCACHE:
647  case WDSF_VERIFY:
648  case WDSF_SEEK:
649  case SET_FEATURES:
650  case WDCC_SETMULTI:
651  case WDCC_IDLE:
653  action = ACT_CMD_COMPLETE;
654  break;
655 
656  // Supported PIO data-in commands
657  case WDCC_IDENTIFY:
659  cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
661  action = ACT_DATA_READY;
662  break;
663 
664  case WDCC_READMULTI:
665  case WDCC_READ:
666  if (!(cmdReg.drive & DRIVE_LBA_BIT))
667  panic("Attempt to perform CHS access, only supports LBA\n");
668 
669  if (cmdReg.sec_count == 0)
670  cmdBytes = cmdBytesLeft = (256 * SectorSize);
671  else
673 
674  curSector = getLBABase();
675 
678  action = ACT_DATA_READY;
679  break;
680 
681  // Supported PIO data-out commands
682  case WDCC_WRITEMULTI:
683  case WDCC_WRITE:
684  if (!(cmdReg.drive & DRIVE_LBA_BIT))
685  panic("Attempt to perform CHS access, only supports LBA\n");
686 
687  if (cmdReg.sec_count == 0)
688  cmdBytes = cmdBytesLeft = (256 * SectorSize);
689  else
691  DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
692  curSector = getLBABase();
693 
695  action = ACT_DATA_READY;
696  break;
697 
698  // Supported DMA commands
699  case WDCC_WRITEDMA:
700  dmaRead = true; // a write to the disk is a DMA read from memory
702  case WDCC_READDMA:
703  if (!(cmdReg.drive & DRIVE_LBA_BIT))
704  panic("Attempt to perform CHS access, only supports LBA\n");
705 
706  if (cmdReg.sec_count == 0)
707  cmdBytes = cmdBytesLeft = (256 * SectorSize);
708  else
710  DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n", cmdBytesLeft);
711 
712  curSector = getLBABase();
713 
715  action = ACT_DMA_READY;
716  break;
717 
718  default:
719  panic("Unsupported ATA command: %#x\n", cmdReg.command);
720  }
721 
722  if (action != ACT_NONE) {
723  // set the BSY bit
725  // clear the DRQ bit
727  // clear the DF bit
728  status &= ~STATUS_DF_BIT;
729 
730  updateState(action);
731  }
732 }
733 
735 // Handle setting and clearing interrupts
737 
738 void
740 {
741  DPRINTF(IdeDisk, "Posting Interrupt\n");
742  if (intrPending)
743  panic("Attempt to post an interrupt with one pending\n");
744 
745  intrPending = true;
746 
747  // talk to controller to set interrupt
748  if (ctrl) {
749  ctrl->intrPost();
750  }
751 }
752 
753 void
755 {
756  DPRINTF(IdeDisk, "Clearing Interrupt\n");
757  if (!intrPending)
758  panic("Attempt to clear a non-pending interrupt\n");
759 
760  intrPending = false;
761 
762  // talk to controller to clear interrupt
763  if (ctrl)
764  ctrl->intrClear();
765 }
766 
768 // Manage the device internal state machine
770 
771 void
773 {
774  switch (devState) {
775  case Device_Srst:
776  if (action == ACT_SRST_SET) {
777  // set the BSY bit
779  } else if (action == ACT_SRST_CLEAR) {
780  // clear the BSY bit
782 
783  // reset the device state
784  reset(devID);
785  }
786  break;
787 
788  case Device_Idle_S:
789  if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
791  } else if (action == ACT_CMD_WRITE) {
792  startCommand();
793  }
794 
795  break;
796 
797  case Device_Idle_SI:
798  if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
800  intrClear();
801  } else if (action == ACT_STAT_READ || isIENSet()) {
803  intrClear();
804  } else if (action == ACT_CMD_WRITE) {
805  intrClear();
806  startCommand();
807  }
808 
809  break;
810 
811  case Device_Idle_NS:
812  if (action == ACT_SELECT_WRITE && isDEVSelect()) {
813  if (!isIENSet() && intrPending) {
815  intrPost();
816  }
817  if (isIENSet() || !intrPending) {
819  }
820  }
821  break;
822 
823  case Command_Execution:
824  if (action == ACT_CMD_COMPLETE) {
825  // clear the BSY bit
826  setComplete();
827 
828  if (!isIENSet()) {
830  intrPost();
831  } else {
833  }
834  }
835  break;
836 
837  case Prepare_Data_In:
838  if (action == ACT_CMD_ERROR) {
839  // clear the BSY bit
840  setComplete();
841 
842  if (!isIENSet()) {
844  intrPost();
845  } else {
847  }
848  } else if (action == ACT_DATA_READY) {
849  // clear the BSY bit
851  // set the DRQ bit
853 
854  // copy the data into the data buffer
855  if (cmdReg.command == WDCC_IDENTIFY ||
857  // Reset the drqBytes for this block
858  drqBytesLeft = sizeof(struct ataparams);
859 
860  memcpy((void *)dataBuffer, (void *)&driveID,
861  sizeof(struct ataparams));
862  } else {
863  // Reset the drqBytes for this block
865 
867  }
868 
869  // put the first two bytes into the data register
870  memcpy((void *)&cmdReg.data, (void *)dataBuffer,
871  sizeof(uint16_t));
872 
873  if (!isIENSet()) {
875  intrPost();
876  } else {
878  }
879  }
880  break;
881 
882  case Data_Ready_INTRQ_In:
883  if (action == ACT_STAT_READ) {
885  intrClear();
886  }
887  break;
888 
889  case Transfer_Data_In:
890  if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
891  if (action == ACT_DATA_READ_BYTE) {
892  panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
893  } else {
894  drqBytesLeft -= 2;
895  cmdBytesLeft -= 2;
896 
897  // copy next short into data registers
898  if (drqBytesLeft)
899  memcpy((void *)&cmdReg.data,
900  (void *)&dataBuffer[SectorSize - drqBytesLeft],
901  sizeof(uint16_t));
902  }
903 
904  if (drqBytesLeft == 0) {
905  if (cmdBytesLeft == 0) {
906  // Clear the BSY bit
907  setComplete();
909  } else {
911  // set the BSY_BIT
913  // clear the DRQ_BIT
915 
919  }
920  }
921  }
922  break;
923 
924  case Prepare_Data_Out:
925  if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
926  // clear the BSY bit
927  setComplete();
928 
929  if (!isIENSet()) {
931  intrPost();
932  } else {
934  }
935  } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
936  // clear the BSY bit
938  // set the DRQ bit
940 
941  // clear the data buffer to get it ready for writes
942  memset(dataBuffer, 0, MAX_DMA_SIZE);
943 
944  // reset the drqBytes for this block
946 
947  if (cmdBytesLeft == cmdBytes || isIENSet()) {
949  } else {
951  intrPost();
952  }
953  }
954  break;
955 
957  if (action == ACT_STAT_READ) {
959  intrClear();
960  }
961  break;
962 
963  case Transfer_Data_Out:
964  if (action == ACT_DATA_WRITE_BYTE ||
965  action == ACT_DATA_WRITE_SHORT) {
966 
967  if (action == ACT_DATA_READ_BYTE) {
968  panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
969  } else {
970  // copy the latest short into the data buffer
971  memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
972  (void *)&cmdReg.data,
973  sizeof(uint16_t));
974 
975  drqBytesLeft -= 2;
976  cmdBytesLeft -= 2;
977  }
978 
979  if (drqBytesLeft == 0) {
980  // copy the block to the disk
982 
983  // set the BSY bit
985  // set the seek bit
987  // clear the DRQ bit
989 
991 
995  }
996  }
997  break;
998 
999  case Prepare_Data_Dma:
1000  if (action == ACT_CMD_ERROR) {
1001  // clear the BSY bit
1002  setComplete();
1003 
1004  if (!isIENSet()) {
1006  intrPost();
1007  } else {
1009  }
1010  } else if (action == ACT_DMA_READY) {
1011  // clear the BSY bit
1012  status &= ~STATUS_BSY_BIT;
1013  // set the DRQ bit
1015 
1017 
1018  if (dmaState != Dma_Idle)
1019  panic("Inconsistent DMA state, should be Dma_Idle\n");
1020 
1021  dmaState = Dma_Start;
1022  // wait for the write to the DMA start bit
1023  }
1024  break;
1025 
1026  case Transfer_Data_Dma:
1027  if (action == ACT_CMD_ERROR) {
1028  dmaAborted = true;
1030  } else if (action == ACT_DMA_DONE) {
1031  // clear the BSY bit
1032  setComplete();
1033  // set the seek bit
1035  // clear the controller state for DMA transfer
1036  ctrl->setDmaComplete(this);
1037 
1038  if (!isIENSet()) {
1040  intrPost();
1041  } else {
1043  }
1044  }
1045  break;
1046 
1047  case Device_Dma_Abort:
1048  if (action == ACT_CMD_ERROR) {
1049  setComplete();
1051  ctrl->setDmaComplete(this);
1052  dmaAborted = false;
1053  dmaState = Dma_Idle;
1054 
1055  if (!isIENSet()) {
1057  intrPost();
1058  } else {
1060  }
1061  } else {
1062  DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
1063  }
1064  break;
1065 
1066  default:
1067  panic("Unknown IDE device state: %#x\n", devState);
1068  }
1069 }
1070 
1071 void
1073 {
1074  // Check all outstanding events to see if they are scheduled
1075  // these are all mutually exclusive
1076  Tick reschedule = 0;
1077  Events_t event = None;
1078 
1079  int eventCount = 0;
1080 
1081  if (dmaTransferEvent.scheduled()) {
1082  reschedule = dmaTransferEvent.when();
1083  event = Transfer;
1084  eventCount++;
1085  }
1086  if (dmaReadWaitEvent.scheduled()) {
1087  reschedule = dmaReadWaitEvent.when();
1088  event = ReadWait;
1089  eventCount++;
1090  }
1091  if (dmaWriteWaitEvent.scheduled()) {
1092  reschedule = dmaWriteWaitEvent.when();
1093  event = WriteWait;
1094  eventCount++;
1095  }
1096  if (dmaPrdReadEvent.scheduled()) {
1097  reschedule = dmaPrdReadEvent.when();
1098  event = PrdRead;
1099  eventCount++;
1100  }
1101  if (dmaReadEvent.scheduled()) {
1102  reschedule = dmaReadEvent.when();
1103  event = DmaRead;
1104  eventCount++;
1105  }
1106  if (dmaWriteEvent.scheduled()) {
1107  reschedule = dmaWriteEvent.when();
1108  event = DmaWrite;
1109  eventCount++;
1110  }
1111 
1112  assert(eventCount <= 1);
1113 
1114  SERIALIZE_SCALAR(reschedule);
1116 
1117  // Serialize device registers
1128 
1129  // Serialize the PRD related information
1134 
1136  // Serialize current transfer related information
1147 }
1148 
1149 void
1151 {
1152  // Reschedule events that were outstanding
1153  // these are all mutually exclusive
1154  Tick reschedule = 0;
1155  Events_t event = None;
1156 
1157  UNSERIALIZE_SCALAR(reschedule);
1159 
1160  switch (event) {
1161  case None : break;
1162  case Transfer : schedule(dmaTransferEvent, reschedule); break;
1163  case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
1164  case WriteWait : schedule(dmaWriteWaitEvent, reschedule); break;
1165  case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
1166  case DmaRead : schedule(dmaReadEvent, reschedule); break;
1167  case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1168  }
1169 
1170  // Unserialize device registers
1181 
1182  // Unserialize the PRD related information
1187 
1189  // Unserialize current transfer related information
1200 }
1201 
1202 IdeDisk *
1203 IdeDiskParams::create()
1204 {
1205  return new IdeDisk(this);
1206 }
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:163
#define DPRINTF(x,...)
Definition: trace.hh:225
#define DATA_OFFSET
Definition: ide_disk.hh:96
bool nIENBit
Interrupt enable bit.
Definition: ide_disk.hh:235
bool next()
Advance generator to next chunk.
#define SECTOR_OFFSET
Definition: ide_disk.hh:100
uint8_t head
Definition: ide_disk.hh:133
uint16_t atap_extensions
Definition: ide_atareg.h:127
#define CONTROL_RST_BIT
Definition: ide_disk.hh:112
void dmaWriteDone()
Definition: ide_disk.cc:550
void dmaPrdReadDone()
Definition: ide_disk.cc:355
void reset(int id)
Reset the device state.
Definition: ide_disk.cc:143
void writeCommand(const Addr offset, int size, const uint8_t *data)
Definition: ide_disk.cc:262
~IdeDisk()
Delete the data buffer.
Definition: ide_disk.cc:136
#define MAX_DMA_SIZE
Definition: ide_disk.hh:61
DmaState_t dmaState
Dma state.
Definition: ide_disk.hh:239
Addr pciToDma(Addr pci_addr) const
Definition: device.hh:194
ChunkGenerator * dmaWriteCG
Definition: ide_disk.hh:323
EventFunctionWrapper dmaReadEvent
Definition: ide_disk.hh:330
#define WDCC_FLUSHCACHE
Definition: ide_wdcreg.h:100
uint8_t atap_piomode_supp
Definition: ide_atareg.h:145
void doDmaRead()
Definition: ide_disk.cc:424
#define LCYL_OFFSET
Definition: ide_disk.hh:101
bool isDiskSelected(IdeDisk *diskPtr)
See if a disk is selected based on its pointer.
Definition: ide_ctrl.cc:143
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay=0)
Definition: dma_device.hh:175
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:391
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: ide_disk.cc:1072
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: ide_disk.cc:1150
uint32_t baseAddr
Definition: ide_disk.hh:70
Device model for an IDE disk.
uint8_t atap_capabilities1
Definition: ide_atareg.h:105
void doDmaTransfer()
Definition: ide_disk.cc:334
#define CONTROL_OFFSET
Definition: ide_disk.hh:108
void startCommand()
Definition: ide_disk.cc:623
uint32_t getByteCount()
Definition: ide_disk.hh:84
#define WDCC_STANDBY_IMMED
Definition: ide_wdcreg.h:108
uint8_t error
Definition: ide_disk.hh:126
PrdEntry_t entry
Definition: ide_disk.hh:77
#define STATUS_OFFSET
Definition: ide_disk.hh:105
#define ALTSTAT_OFFSET
Definition: ide_disk.hh:109
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:130
DiskImage * image
The image that contains the data of this disk.
Definition: ide_disk.hh:211
Simple PCI IDE controller with bus mastering capability and UDMA modeled after controller in the Inte...
Bitfield< 23, 0 > offset
Definition: types.hh:152
#define NSECTOR_OFFSET
Definition: ide_disk.hh:99
#define DRIVE_LBA_BIT
Definition: ide_disk.hh:119
bool dmaAborted
DMA Aborted.
Definition: ide_disk.hh:253
uint16_t atap_hwreset_res
Definition: ide_atareg.h:242
uint32_t drqBytesLeft
Number of bytes left in DRQ block.
Definition: ide_disk.hh:227
Definition: cprintf.cc:40
void updateState(DevAction_t action)
Definition: ide_disk.cc:772
Stats::Scalar dmaWriteBytes
Definition: ide_disk.hh:259
#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:754
bool isDEVSelect()
Definition: ide_disk.cc:187
#define DEV0
Definition: ide_disk.hh:121
uint8_t atap_model[40]
Definition: ide_atareg.h:101
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:308
#define WDCC_IDENTIFY
Definition: ide_wdcreg.h:101
#define SET_FEATURES
Definition: ide_wdcreg.h:102
void dmaReadDone()
Definition: ide_disk.cc:463
uint8_t command
Definition: ide_disk.hh:135
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:770
unsigned size() const
Return size in bytes of current chunk.
uint8_t drive
Definition: ide_disk.hh:132
Tick curTick()
The current simulated tick.
Definition: core.hh:44
#define STATUS_SEEK_BIT
Definition: ide_disk.hh:117
#define WDCC_IDLE
Definition: ide_wdcreg.h:104
#define SERIALIZE_ENUM(scalar)
Definition: serialize.hh:786
uint8_t sec_count
Definition: ide_disk.hh:127
uint32_t cmdBytesLeft
Number of bytes left in command data transfer.
Definition: ide_disk.hh:225
#define M5_FALLTHROUGH
Definition: compiler.hh:84
#define WDSF_VERIFY
Definition: ide_wdcreg.h:158
void readCommand(const Addr offset, int size, uint8_t *data)
Definition: ide_disk.cc:206
#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:61
void dmaRead(Addr addr, int size, Event *event, uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay=0)
Definition: dma_device.hh:188
#define HCYL_OFFSET
Definition: ide_disk.hh:102
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:379
uint8_t atap_udmamode_supp
Definition: ide_atareg.h:231
#define CONTROL_IEN_BIT
Definition: ide_disk.hh:113
#define COMMAND_OFFSET
Definition: ide_disk.hh:106
virtual std::streampos write(const uint8_t *data, std::streampos offset)=0
uint32_t getLBABase()
Definition: ide_disk.hh:357
uint16_t byteCount
Definition: ide_disk.hh:71
#define SectorSize
Definition: disk_image.hh:44
struct ataparams driveID
Drive identification structure for this disk.
Definition: ide_disk.hh:219
IdeDisk(const Params *p)
Definition: ide_disk.cc:62
uint16_t atap_ata_major
Definition: ide_atareg.h:175
EventFunctionWrapper dmaWriteEvent
Definition: ide_disk.hh:333
void schedule(Event &event, Tick when)
Definition: eventq.hh:934
#define WDCC_READDMA
Definition: ide_wdcreg.h:93
#define FEATURES_OFFSET
Definition: ide_disk.hh:98
void writeControl(const Addr offset, int size, const uint8_t *data)
Definition: ide_disk.cc:310
void abortDma()
Definition: ide_disk.cc:611
void reschedule(Event &event, Tick when, bool always=false)
Definition: eventq.hh:952
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:140
uint32_t getBaseAddr()
Definition: ide_disk.hh:79
#define ULL(N)
uint64_t constant
Definition: types.hh:48
#define DMA_BACKOFF_PERIOD
Definition: ide_disk.hh:59
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:229
bool dmaPending() const
Definition: dma_device.hh:201
#define SERIALIZE_ARRAY(member, size)
Definition: serialize.hh:805
Bitfield< 10, 5 > event
Addr pageBytes
Size of OS pages.
Definition: ide_disk.hh:243
uint8_t status
Status register.
Definition: ide_disk.hh:233
uint16_t atap_cylinders
Definition: ide_atareg.h:90
EventFunctionWrapper dmaPrdReadEvent
Definition: ide_disk.hh:327
DevState_t devState
Device state.
Definition: ide_disk.hh:237
void doDmaWrite()
Definition: ide_disk.cc:509
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:763
EventFunctionWrapper dmaWriteWaitEvent
Definition: ide_disk.hh:324
uint16_t data
Definition: ide_disk.hh:125
enum DevAction DevAction_t
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:459
ChunkGenerator * dmaReadCG
Definition: ide_disk.hh:317
uint16_t endOfTable
Definition: ide_disk.hh:72
Derived & name(const std::string &name)
Set the name and marks this stat to print at the end of simulation.
Definition: statistics.hh:276
uint32_t cmdBytes
Number of bytes in command data transfer.
Definition: ide_disk.hh:223
#define STATUS_BSY_BIT
Definition: ide_disk.hh:114
#define DRIVE_OFFSET
Definition: ide_disk.hh:104
virtual const std::string name() const
Definition: sim_object.hh:129
#define UNSERIALIZE_ARRAY(member, size)
Definition: serialize.hh:813
#define WDCC_WRITE
Definition: ide_wdcreg.h:81
PrdTableEntry curPrd
PRD entry.
Definition: ide_disk.hh:247
uint8_t cyl_low
Definition: ide_disk.hh:129
IDE Disk device model.
Definition: ide_disk.hh:205
CommandReg_t cmdReg
Command block registers.
Definition: ide_disk.hh:231
#define WDCC_READMULTI
Definition: ide_wdcreg.h:89
bool intrPending
Interrupt pending.
Definition: ide_disk.hh:251
std::ostream CheckpointOut
Definition: serialize.hh:63
unsigned complete() const
Number of bytes we have already chunked up.
EventFunctionWrapper dmaReadWaitEvent
Definition: ide_disk.hh:318
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:241
Disk Image Interfaces.
bool isIENSet()
Definition: ide_disk.hh:344
#define STATUS_DF_BIT
Definition: ide_disk.hh:118
void startDma(const uint32_t &prdTableBase)
Definition: ide_disk.cc:593
void doDmaDataWrite()
Definition: ide_disk.cc:486
#define UNSERIALIZE_ENUM(scalar)
Definition: serialize.hh:793
#define WDCC_SETMULTI
Definition: ide_wdcreg.h:91
Addr pciToDma(Addr pciAddr)
Definition: ide_disk.cc:193
#define STATUS_DRQ_BIT
Definition: ide_disk.hh:116
uint8_t sec_num
Definition: ide_disk.hh:128
#define ATAPI_IDENTIFY_DEVICE
Definition: ide_wdcreg.h:171
Stats::Scalar dmaReadFullPages
Definition: ide_disk.hh:255
#define STATUS_DRDY_BIT
Definition: ide_disk.hh:115
#define ERROR_OFFSET
Definition: ide_disk.hh:97
IdeController * ctrl
The IDE controller for this disk.
Definition: ide_disk.hh:209
#define WDSF_SEEK
Definition: ide_wdcreg.h:157
void writeDisk(uint32_t sector, uint8_t *data)
Definition: ide_disk.cc:579
#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:309
EventFunctionWrapper dmaTransferEvent
Definition: ide_disk.hh:312
uint8_t * dataBuffer
Data buffer for transfers.
Definition: ide_disk.hh:221
Addr addr() const
Return starting address of current chunk.
virtual void regStats()
Callback to set stat parameters.
Definition: group.cc:64
#define MAX_MULTSECT
Definition: ide_disk.hh:63
Declaration and inline definition of ChunkGenerator object.
uint16_t getEOT()
Definition: ide_disk.hh:90
void readControl(const Addr offset, int size, uint8_t *data)
Definition: ide_disk.cc:252
uint32_t atap_capacity
Definition: ide_atareg.h:140
Bitfield< 0 > p
uint8_t atap_dmamode_supp
Definition: ide_atareg.h:143
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:499
void readDisk(uint32_t sector, uint8_t *data)
Definition: ide_disk.cc:569
const char data[]
void setComplete()
Definition: ide_disk.hh:347
void setDmaComplete(IdeDisk *disk)
Definition: ide_ctrl.cc:156
void intrPost()
Definition: ide_ctrl.cc:149
Stats::Scalar dmaWriteFullPages
Definition: ide_disk.hh:258
void intrClear()
Definition: device.hh:199
#define DEV1
Definition: ide_disk.hh:122
Abstract superclass for simulation objects.
Definition: sim_object.hh:93
int diskDelay
The disk delay in microseconds.
Definition: ide_disk.hh:215
#define WDCC_WRITEMULTI
Definition: ide_wdcreg.h:90
void intrPost()
Definition: ide_disk.cc:739
uint16_t atap_heads
Definition: ide_atareg.h:92
Stats::Scalar dmaWriteTxs
Definition: ide_disk.hh:260

Generated on Thu May 28 2020 16:21:33 for gem5 by doxygen 1.8.13