gem5  v22.1.0.0
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 "base/bitfield.hh"
53 #include "base/chunk_generator.hh"
54 #include "base/compiler.hh"
55 #include "base/cprintf.hh" // csprintf
56 #include "base/trace.hh"
57 #include "debug/IdeDisk.hh"
59 #include "dev/storage/ide_ctrl.hh"
60 #include "sim/cur_tick.hh"
61 #include "sim/sim_object.hh"
62 
63 namespace gem5
64 {
65 
67  : SimObject(p), image(p.image), diskDelay(p.delay), ideDiskStats(this),
68  dmaTransferEvent([this]{ doDmaTransfer(); }, name()),
69  dmaReadWaitEvent([this]{ doDmaRead(); }, name()),
70  dmaWriteWaitEvent([this]{ doDmaWrite(); }, name()),
71  dmaPrdReadEvent([this]{ dmaPrdReadDone(); }, name()),
72  dmaReadEvent([this]{ dmaReadDone(); }, name()),
73  dmaWriteEvent([this]{ dmaWriteDone(); }, name())
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
111  driveID.atap_multi = MAX_MULTSECT;
112  // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
113  driveID.atap_capabilities1 = 0x7;
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
121  driveID.atap_curmulti = MAX_MULTSECT;
122  driveID.atap_curmulti_valid = 0x1;
123  // Number of sectors on disk
124  driveID.atap_capacity = lba_size;
125  // Multiword DMA mode 2 and below supported
126  driveID.atap_dmamode_supp = 0x4;
127  // Set PIO mode 4 and 3 supported
128  driveID.atap_piomode_supp = 0x3;
129  // Set DMA mode 4 and below supported
130  driveID.atap_udmamode_supp = 0x1f;
131  // Statically set hardware config word
132  driveID.atap_hwreset_res = 0x4001;
133 
134  //arbitrary for now...
135  driveID.atap_ata_major = WDC_VER_ATA7;
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  pendingInterrupt = 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 channel->selected() == this;
192 }
193 
194 Addr
196 {
197  panic_if(!ctrl, "Access to unset controller!");
198  return ctrl->pciToDma(pciAddr);
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 
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  }
346 
349  return;
350  } else {
352  (uint8_t*)&curPrd.entry);
353  }
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 
394  : statistics::Group(parent, "IdeDisk"),
395  ADD_STAT(dmaReadFullPages, statistics::units::Count::get(),
396  "Number of full page size DMA reads (not PRD)."),
397  ADD_STAT(dmaReadBytes, statistics::units::Byte::get(),
398  "Number of bytes transfered via DMA reads (not PRD)."),
399  ADD_STAT(dmaReadTxs, statistics::units::Count::get(),
400  "Number of DMA read transactions (not PRD)."),
401  ADD_STAT(dmaWriteFullPages, statistics::units::Count::get(),
402  "Number of full page size DMA writes."),
403  ADD_STAT(dmaWriteBytes, statistics::units::Byte::get(),
404  "Number of bytes transfered via DMA writes."),
405  ADD_STAT(dmaWriteTxs, statistics::units::Count::get(),
406  "Number of DMA write transactions.")
407 {
408 }
409 
410 void
412 {
413  if (dmaAborted) {
414  DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
415  if (dmaReadCG)
416  delete dmaReadCG;
417  dmaReadCG = NULL;
419  return;
420  }
421 
422  if (!dmaReadCG) {
423  // clear out the data buffer
424  memset(dataBuffer, 0, MAX_DMA_SIZE);
427 
428  }
431  return;
432  } else if (!dmaReadCG->done()) {
433  assert(dmaReadCG->complete() < MAX_DMA_SIZE);
438  if (dmaReadCG->size() == chunkBytes)
440  dmaReadCG->next();
441  } else {
442  assert(dmaReadCG->done());
443  delete dmaReadCG;
444  dmaReadCG = NULL;
445  dmaReadDone();
446  }
447 }
448 
449 void
451 {
452  uint32_t bytesWritten = 0;
453 
454  // write the data to the disk image
455  for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
456  bytesWritten += SectorSize) {
457 
459  writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
460  }
461 
462  // check for the EOT
463  if (curPrd.getEOT()) {
464  assert(cmdBytesLeft == 0);
465  dmaState = Dma_Idle;
467  } else {
468  doDmaTransfer();
469  }
470 }
471 
472 void
474 {
476  Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
477  uint32_t bytesRead = 0;
478 
479  DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
480  diskDelay, totalDiskDelay);
481 
482  memset(dataBuffer, 0, MAX_DMA_SIZE);
483  assert(cmdBytesLeft <= MAX_DMA_SIZE);
484  while (bytesRead < curPrd.getByteCount()) {
485  readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
486  bytesRead += SectorSize;
488  }
489  DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
490  bytesRead, cmdBytesLeft);
491 
492  schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
493 }
494 
495 void
497 {
498  if (dmaAborted) {
499  DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
500  if (dmaWriteCG)
501  delete dmaWriteCG;
502  dmaWriteCG = NULL;
504  return;
505  }
506  if (!dmaWriteCG) {
507  // clear out the data buffer
510  }
513  DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
514  return;
515  } else if (!dmaWriteCG->done()) {
516  assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
519  DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
523  if (dmaWriteCG->size() == chunkBytes)
525  dmaWriteCG->next();
526  } else {
527  DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
529  assert(dmaWriteCG->done());
530  delete dmaWriteCG;
531  dmaWriteCG = NULL;
532  dmaWriteDone();
533  }
534 }
535 
536 void
538 {
540  "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
542  // check for the EOT
543  if (curPrd.getEOT()) {
544  assert(cmdBytesLeft == 0);
545  dmaState = Dma_Idle;
547  } else {
548  doDmaTransfer();
549  }
550 }
551 
553 // Disk utility routines
555 
556 void
557 IdeDisk::readDisk(uint32_t sector, uint8_t *data)
558 {
559  uint32_t bytesRead = image->read(data, sector);
560 
561  panic_if(bytesRead != SectorSize,
562  "Can't read from %s. Only %d of %d read. errno=%d",
563  name(), bytesRead, SectorSize, errno);
564 }
565 
566 void
567 IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
568 {
569  uint32_t bytesWritten = image->write(data, sector);
570 
571  panic_if(bytesWritten != SectorSize,
572  "Can't write to %s. Only %d of %d written. errno=%d",
573  name(), bytesWritten, SectorSize, errno);
574 }
575 
577 // Setup and handle commands
579 
580 void
581 IdeDisk::startDma(const uint32_t &prdTableBase)
582 {
584  "Inconsistent DMA state, should be in Dma_Start!");
585 
587  "Inconsistent device state for DMA start!");
588 
589  // PRD base address is given by bits 31:2
590  curPrdAddr = pciToDma((Addr)(prdTableBase & ~0x3ULL));
591 
593 
594  // schedule dma transfer (doDmaTransfer)
596 }
597 
598 void
600 {
602  "Inconsistent DMA state, should be Start or Transfer!");
603 
605  "Inconsistent device state, should be Transfer or Prepare!");
606 
608 }
609 
610 void
612 {
613  DevAction_t action = ACT_NONE;
614  uint32_t size = 0;
615  dmaRead = false;
616 
617  // Clear any existing errors.
618  replaceBits(status, 0, 0);
619  replaceBits(cmdReg.error, 2, 0);
620 
621  // Decode commands
622  switch (cmdReg.command) {
623  // Supported non-data commands
625  size = (uint32_t)image->size() - 1;
626  cmdReg.sec_num = (size & 0xff);
627  cmdReg.cyl_low = ((size & 0xff00) >> 8);
628  cmdReg.cyl_high = ((size & 0xff0000) >> 16);
629  cmdReg.head = ((size & 0xf000000) >> 24);
630 
632  action = ACT_CMD_COMPLETE;
633  break;
634 
635  case WDCC_RECAL:
636  case WDCC_IDP:
637  case WDCC_STANDBY_IMMED:
638  case WDCC_FLUSHCACHE:
639  case WDSF_VERIFY:
640  case WDSF_SEEK:
641  case SET_FEATURES:
642  case WDCC_SETMULTI:
643  case WDCC_IDLE:
645  action = ACT_CMD_COMPLETE;
646  break;
647 
648  // Supported PIO data-in commands
649  case WDCC_IDENTIFY:
650  cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
652  action = ACT_DATA_READY;
653  break;
654 
656  // We're not an ATAPI device, so this command isn't implemented.
658  action = ACT_CMD_ERROR;
659  replaceBits(cmdReg.error, 2, 1);
660  replaceBits(status, 0, 1);
661  break;
662 
663  case WDCC_READMULTI:
664  case WDCC_READ:
666  "Attempt to perform CHS access, only supports LBA");
667 
668  if (cmdReg.sec_count == 0)
669  cmdBytes = cmdBytesLeft = (256 * SectorSize);
670  else
672 
673  curSector = getLBABase();
674 
677  action = ACT_DATA_READY;
678  break;
679 
680  // Supported PIO data-out commands
681  case WDCC_WRITEMULTI:
682  case WDCC_WRITE:
684  "Attempt to perform CHS access, only supports LBA");
685 
686  if (cmdReg.sec_count == 0)
687  cmdBytes = cmdBytesLeft = (256 * SectorSize);
688  else
690  DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
691  curSector = getLBABase();
692 
694  action = ACT_DATA_READY;
695  break;
696 
697  // Supported DMA commands
698  case WDCC_WRITEDMA:
699  dmaRead = true; // a write to the disk is a DMA read from memory
700  [[fallthrough]];
701  case WDCC_READDMA:
703  "Attempt to perform CHS access, only supports LBA");
704 
705  if (cmdReg.sec_count == 0)
706  cmdBytes = cmdBytesLeft = (256 * SectorSize);
707  else
709  DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n",
710  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");
743  "Attempt to post an interrupt with one pending");
744 
745  pendingInterrupt = true;
746 
747  assert(channel);
749 }
750 
751 void
753 {
754  DPRINTF(IdeDisk, "Clearing Interrupt\n");
755  panic_if(!pendingInterrupt, "Attempt to clear a non-pending interrupt");
756 
757  pendingInterrupt = false;
758 
759  assert(channel);
761 }
762 
764 // Manage the device internal state machine
766 
767 void
769 {
770  switch (devState) {
771  case Device_Srst:
772  if (action == ACT_SRST_SET) {
773  // set the BSY bit
775  } else if (action == ACT_SRST_CLEAR) {
776  // clear the BSY bit
778 
779  // reset the device state
780  reset(devID);
781  }
782  break;
783 
784  case Device_Idle_S:
785  if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
787  } else if (action == ACT_CMD_WRITE) {
788  startCommand();
789  }
790 
791  break;
792 
793  case Device_Idle_SI:
794  if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
796  clearInterrupt();
797  } else if (action == ACT_STAT_READ || isIENSet()) {
799  clearInterrupt();
800  } else if (action == ACT_CMD_WRITE) {
801  clearInterrupt();
802  startCommand();
803  }
804 
805  break;
806 
807  case Device_Idle_NS:
808  if (action == ACT_SELECT_WRITE && isDEVSelect()) {
809  if (!isIENSet() && pendingInterrupt) {
811  postInterrupt();
812  }
813  if (isIENSet() || !pendingInterrupt) {
815  }
816  }
817  break;
818 
819  case Command_Execution:
820  if (action == ACT_CMD_ERROR || action == ACT_CMD_COMPLETE) {
821  // clear the BSY bit
822  setComplete();
823 
824  if (!isIENSet()) {
826  postInterrupt();
827  } else {
829  }
830  }
831  break;
832 
833  case Prepare_Data_In:
834  if (action == ACT_CMD_ERROR) {
835  // clear the BSY bit
836  setComplete();
837 
838  if (!isIENSet()) {
840  postInterrupt();
841  } else {
843  }
844  } else if (action == ACT_DATA_READY) {
845  // clear the BSY bit
847  // set the DRQ bit
849 
850  // copy the data into the data buffer
851  if (cmdReg.command == WDCC_IDENTIFY ||
853  // Reset the drqBytes for this block
854  drqBytesLeft = sizeof(struct ataparams);
855 
856  memcpy((void *)dataBuffer, (void *)&driveID,
857  sizeof(struct ataparams));
858  } else {
859  // Reset the drqBytes for this block
861 
863  }
864 
865  // put the first two bytes into the data register
866  memcpy((void *)&cmdReg.data, (void *)dataBuffer,
867  sizeof(uint16_t));
868 
869  if (!isIENSet()) {
871  postInterrupt();
872  } else {
874  }
875  }
876  break;
877 
878  case Data_Ready_INTRQ_In:
879  if (action == ACT_STAT_READ) {
881  clearInterrupt();
882  }
883  break;
884 
885  case Transfer_Data_In:
886  if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
887  if (action == ACT_DATA_READ_BYTE) {
888  panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
889  } else {
890  drqBytesLeft -= 2;
891  cmdBytesLeft -= 2;
892 
893  // copy next short into data registers
894  if (drqBytesLeft)
895  memcpy((void *)&cmdReg.data,
896  (void *)&dataBuffer[SectorSize - drqBytesLeft],
897  sizeof(uint16_t));
898  }
899 
900  if (drqBytesLeft == 0) {
901  if (cmdBytesLeft == 0) {
902  // Clear the BSY bit
903  setComplete();
905  } else {
907  // set the BSY_BIT
909  // clear the DRQ_BIT
911 
915  }
916  }
917  }
918  break;
919 
920  case Prepare_Data_Out:
921  if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
922  // clear the BSY bit
923  setComplete();
924 
925  if (!isIENSet()) {
927  postInterrupt();
928  } else {
930  }
931  } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
932  // clear the BSY bit
934  // set the DRQ bit
936 
937  // clear the data buffer to get it ready for writes
938  memset(dataBuffer, 0, MAX_DMA_SIZE);
939 
940  // reset the drqBytes for this block
942 
943  if (cmdBytesLeft == cmdBytes || isIENSet()) {
945  } else {
947  postInterrupt();
948  }
949  }
950  break;
951 
953  if (action == ACT_STAT_READ) {
955  clearInterrupt();
956  }
957  break;
958 
959  case Transfer_Data_Out:
960  if (action == ACT_DATA_WRITE_BYTE ||
961  action == ACT_DATA_WRITE_SHORT) {
962 
963  if (action == ACT_DATA_READ_BYTE) {
964  panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
965  } else {
966  // copy the latest short into the data buffer
967  memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
968  (void *)&cmdReg.data,
969  sizeof(uint16_t));
970 
971  drqBytesLeft -= 2;
972  cmdBytesLeft -= 2;
973  }
974 
975  if (drqBytesLeft == 0) {
976  // copy the block to the disk
978 
979  // set the BSY bit
981  // set the seek bit
983  // clear the DRQ bit
985 
987 
991  }
992  }
993  break;
994 
995  case Prepare_Data_Dma:
996  if (action == ACT_CMD_ERROR) {
997  // clear the BSY bit
998  setComplete();
999 
1000  if (!isIENSet()) {
1002  postInterrupt();
1003  } else {
1005  }
1006  } else if (action == ACT_DMA_READY) {
1007  // clear the BSY bit
1008  status &= ~STATUS_BSY_BIT;
1009  // set the DRQ bit
1011 
1013 
1014  if (dmaState != Dma_Idle)
1015  panic("Inconsistent DMA state, should be Dma_Idle\n");
1016 
1017  dmaState = Dma_Start;
1018  // wait for the write to the DMA start bit
1019  }
1020  break;
1021 
1022  case Transfer_Data_Dma:
1023  if (action == ACT_CMD_ERROR) {
1024  dmaAborted = true;
1026  } else if (action == ACT_DMA_DONE) {
1027  // clear the BSY bit
1028  setComplete();
1029  // set the seek bit
1031  // clear the controller state for DMA transfer
1033 
1034  if (!isIENSet()) {
1036  postInterrupt();
1037  } else {
1039  }
1040  }
1041  break;
1042 
1043  case Device_Dma_Abort:
1044  if (action == ACT_CMD_ERROR) {
1045  setComplete();
1048  dmaAborted = false;
1049  dmaState = Dma_Idle;
1050 
1051  if (!isIENSet()) {
1053  postInterrupt();
1054  } else {
1056  }
1057  } else {
1058  DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
1059  }
1060  break;
1061 
1062  default:
1063  panic("Unknown IDE device state: %#x\n", devState);
1064  }
1065 }
1066 
1067 void
1069 {
1070  // Check all outstanding events to see if they are scheduled
1071  // these are all mutually exclusive
1072  Tick reschedule = 0;
1073  Events_t event = None;
1074 
1075  int eventCount = 0;
1076 
1077  if (dmaTransferEvent.scheduled()) {
1079  event = Transfer;
1080  eventCount++;
1081  }
1082  if (dmaReadWaitEvent.scheduled()) {
1084  event = ReadWait;
1085  eventCount++;
1086  }
1087  if (dmaWriteWaitEvent.scheduled()) {
1089  event = WriteWait;
1090  eventCount++;
1091  }
1092  if (dmaPrdReadEvent.scheduled()) {
1094  event = PrdRead;
1095  eventCount++;
1096  }
1097  if (dmaReadEvent.scheduled()) {
1099  event = DmaRead;
1100  eventCount++;
1101  }
1102  if (dmaWriteEvent.scheduled()) {
1104  event = DmaWrite;
1105  eventCount++;
1106  }
1107 
1108  assert(eventCount <= 1);
1109 
1112 
1113  // Serialize device registers
1124 
1125  // Serialize the PRD related information
1130 
1132  // Serialize current transfer related information
1138  paramOut(cp, "intrPending", pendingInterrupt);
1143 }
1144 
1145 void
1147 {
1148  // Reschedule events that were outstanding
1149  // these are all mutually exclusive
1150  Tick reschedule = 0;
1151  Events_t event = None;
1152 
1155 
1156  switch (event) {
1157  case None : break;
1158  case Transfer : schedule(dmaTransferEvent, reschedule); break;
1159  case ReadWait : schedule(dmaReadWaitEvent, reschedule); break;
1161  case PrdRead : schedule(dmaPrdReadEvent, reschedule); break;
1162  case DmaRead : schedule(dmaReadEvent, reschedule); break;
1163  case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1164  }
1165 
1166  // Unserialize device registers
1177 
1178  // Unserialize the PRD related information
1183 
1185  // Unserialize current transfer related information
1191  paramIn(cp, "intrPending", pendingInterrupt);
1196 }
1197 
1198 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
Declaration and inline definition of ChunkGenerator object.
const char data[]
This class takes an arbitrary memory region (address/length pair) and generates a series of appropria...
virtual std::streampos write(const uint8_t *data, std::streampos offset)=0
virtual std::streampos size() const =0
virtual std::streampos read(uint8_t *data, std::streampos offset) const =0
void dmaWrite(Addr addr, int size, Event *event, uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay=0)
Definition: dma_device.hh:214
bool dmaPending() const
Definition: dma_device.hh:241
void dmaRead(Addr addr, int size, Event *event, uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay=0)
Definition: dma_device.hh:228
IdeDisk * selected() const
Definition: ide_ctrl.hh:134
IDE Disk device model.
Definition: ide_disk.hh:217
EventFunctionWrapper dmaReadEvent
Definition: ide_disk.hh:344
void startCommand()
Definition: ide_disk.cc:611
uint32_t drqBytesLeft
Number of bytes left in DRQ block.
Definition: ide_disk.hh:240
void dmaReadDone()
Definition: ide_disk.cc:450
void doDmaTransfer()
Definition: ide_disk.cc:334
EventFunctionWrapper dmaPrdReadEvent
Definition: ide_disk.hh:341
void doDmaDataRead()
Definition: ide_disk.cc:381
void startDma(const uint32_t &prdTableBase)
Definition: ide_disk.cc:581
void doDmaDataWrite()
Definition: ide_disk.cc:473
void abortDma()
Definition: ide_disk.cc:599
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: ide_disk.cc:1068
~IdeDisk()
Delete the data buffer.
Definition: ide_disk.cc:138
void writeDisk(uint32_t sector, uint8_t *data)
Definition: ide_disk.cc:567
bool isDEVSelect()
Definition: ide_disk.cc:189
bool nIENBit
Interrupt enable bit.
Definition: ide_disk.hh:248
uint32_t cmdBytes
Number of bytes in command data transfer.
Definition: ide_disk.hh:236
void readControl(const Addr offset, int size, uint8_t *data)
Definition: ide_disk.cc:252
IdeController * ctrl
The IDE controller for this disk.
Definition: ide_disk.hh:220
void writeCommand(const Addr offset, int size, const uint8_t *data)
Definition: ide_disk.cc:262
uint32_t curPrdAddr
PRD table base address.
Definition: ide_disk.hh:258
bool isIENSet()
Definition: ide_disk.hh:358
void clearInterrupt()
Definition: ide_disk.cc:752
void dmaPrdReadDone()
Definition: ide_disk.cc:357
struct ataparams driveID
Drive identification structure for this disk.
Definition: ide_disk.hh:232
void postInterrupt()
Definition: ide_disk.cc:739
IdeDisk(const Params &p)
Definition: ide_disk.cc:66
uint8_t * dataBuffer
Data buffer for transfers.
Definition: ide_disk.hh:234
ChunkGenerator * dmaWriteCG
Definition: ide_disk.hh:337
PrdTableEntry curPrd
PRD entry.
Definition: ide_disk.hh:260
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: ide_disk.cc:1146
IdeDiskParams Params
Definition: ide_disk.hh:281
EventFunctionWrapper dmaWriteEvent
Definition: ide_disk.hh:347
uint32_t curSector
Current sector in access.
Definition: ide_disk.hh:242
bool dmaRead
Dma transaction is a read.
Definition: ide_disk.hh:254
bool pendingInterrupt
Interrupt pending.
Definition: ide_disk.hh:264
DiskImage * image
The image that contains the data of this disk.
Definition: ide_disk.hh:224
void doDmaRead()
Definition: ide_disk.cc:411
EventFunctionWrapper dmaWriteWaitEvent
Definition: ide_disk.hh:338
void doDmaWrite()
Definition: ide_disk.cc:496
void reset(int id)
Reset the device state.
Definition: ide_disk.cc:145
gem5::IdeDisk::IdeDiskStats ideDiskStats
ChunkGenerator * dmaReadCG
Definition: ide_disk.hh:331
void readDisk(uint32_t sector, uint8_t *data)
Definition: ide_disk.cc:557
DevState_t devState
Device state.
Definition: ide_disk.hh:250
int diskDelay
The disk delay in microseconds.
Definition: ide_disk.hh:228
EventFunctionWrapper dmaTransferEvent
Definition: ide_disk.hh:326
void writeControl(const Addr offset, int size, const uint8_t *data)
Definition: ide_disk.cc:310
bool dmaAborted
DMA Aborted.
Definition: ide_disk.hh:266
void dmaWriteDone()
Definition: ide_disk.cc:537
void setComplete()
Definition: ide_disk.hh:362
uint8_t status
Status register.
Definition: ide_disk.hh:246
Addr pciToDma(Addr pciAddr)
Definition: ide_disk.cc:195
Addr chunkBytes
Size of chunks to DMA.
Definition: ide_disk.hh:256
IdeController::Channel * channel
The channel this disk is connected to.
Definition: ide_disk.hh:222
DmaState_t dmaState
Dma state.
Definition: ide_disk.hh:252
void readCommand(const Addr offset, int size, uint8_t *data)
Definition: ide_disk.cc:206
uint32_t cmdBytesLeft
Number of bytes left in command data transfer.
Definition: ide_disk.hh:238
EventFunctionWrapper dmaReadWaitEvent
Definition: ide_disk.hh:332
CommandReg_t cmdReg
Command block registers.
Definition: ide_disk.hh:244
int devID
Device ID (device0=0/device1=1)
Definition: ide_disk.hh:262
void updateState(DevAction_t action)
Definition: ide_disk.cc:768
uint32_t getLBABase()
Definition: ide_disk.hh:373
virtual std::string name() const
Definition: named.hh:47
Addr pciToDma(Addr pci_addr) const
Definition: device.hh:359
uint32_t getByteCount()
Definition: ide_disk.hh:89
uint16_t getEOT()
Definition: ide_disk.hh:95
PrdEntry_t entry
Definition: ide_disk.hh:82
uint32_t getBaseAddr()
Definition: ide_disk.hh:84
Abstract superclass for simulation objects.
Definition: sim_object.hh:148
Statistics container.
Definition: group.hh:94
Disk Image Interfaces.
#define SectorSize
Definition: disk_image.hh:44
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition: group.hh:75
constexpr void replaceBits(T &val, unsigned first, unsigned last, B bit_val)
A convenience function to replace bits first to last of val with bit_val in place.
Definition: bitfield.hh:197
Addr addr() const
Return starting address of current chunk.
Addr complete() const
Number of bytes we have already chunked up.
bool done() const
Are we done? That is, did the last call to next() advance past the end of the region?
Addr size() const
Return size in bytes of current chunk.
bool next()
Advance generator to next chunk.
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:324
@ Running
Running normally.
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:465
void schedule(Event &event, Tick when)
Definition: eventq.hh:1019
void reschedule(Event &event, Tick when, bool always=false)
Definition: eventq.hh:1037
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:508
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
#define SERIALIZE_ENUM(scalar)
Definition: serialize.hh:591
#define UNSERIALIZE_ARRAY(member, size)
Definition: serialize.hh:618
#define SERIALIZE_ARRAY(member, size)
Definition: serialize.hh:610
#define UNSERIALIZE_ENUM(scalar)
Definition: serialize.hh:598
#define WDC_VER_ATA7
Definition: ide_atareg.h:183
Device model for an IDE disk.
#define DATA_OFFSET
Definition: ide_disk.hh:101
#define DEV0
Definition: ide_disk.hh:126
#define ERROR_OFFSET
Definition: ide_disk.hh:102
#define NSECTOR_OFFSET
Definition: ide_disk.hh:104
#define LCYL_OFFSET
Definition: ide_disk.hh:106
#define STATUS_BSY_BIT
Definition: ide_disk.hh:119
#define DEV1
Definition: ide_disk.hh:127
#define DMA_BACKOFF_PERIOD
Definition: ide_disk.hh:62
#define STATUS_SEEK_BIT
Definition: ide_disk.hh:122
#define STATUS_DRQ_BIT
Definition: ide_disk.hh:121
#define STATUS_DF_BIT
Definition: ide_disk.hh:123
#define MAX_MULTSECT
Definition: ide_disk.hh:66
#define CONTROL_RST_BIT
Definition: ide_disk.hh:117
#define MAX_DMA_SIZE
Definition: ide_disk.hh:64
#define FEATURES_OFFSET
Definition: ide_disk.hh:103
#define DRIVE_OFFSET
Definition: ide_disk.hh:109
#define STATUS_DRDY_BIT
Definition: ide_disk.hh:120
#define STATUS_OFFSET
Definition: ide_disk.hh:110
#define DRIVE_LBA_BIT
Definition: ide_disk.hh:124
#define COMMAND_OFFSET
Definition: ide_disk.hh:111
#define ALTSTAT_OFFSET
Definition: ide_disk.hh:114
#define CONTROL_OFFSET
Definition: ide_disk.hh:113
#define CONTROL_IEN_BIT
Definition: ide_disk.hh:118
#define HCYL_OFFSET
Definition: ide_disk.hh:107
#define SECTOR_OFFSET
Definition: ide_disk.hh:105
#define WDSF_READ_NATIVE_MAX
Definition: ide_wdcreg.h:156
#define ATAPI_IDENTIFY_DEVICE
Definition: ide_wdcreg.h:171
#define WDSF_VERIFY
Definition: ide_wdcreg.h:158
#define WDCC_WRITEDMA
Definition: ide_wdcreg.h:94
#define WDCC_RECAL
Definition: ide_wdcreg.h:78
#define WDCC_STANDBY_IMMED
Definition: ide_wdcreg.h:108
#define WDSF_SEEK
Definition: ide_wdcreg.h:157
#define WDCC_IDP
Definition: ide_wdcreg.h:87
#define WDCC_READDMA
Definition: ide_wdcreg.h:93
#define WDCC_IDENTIFY
Definition: ide_wdcreg.h:101
#define WDCC_WRITE
Definition: ide_wdcreg.h:81
#define WDCC_WRITEMULTI
Definition: ide_wdcreg.h:90
#define WDCC_FLUSHCACHE
Definition: ide_wdcreg.h:100
#define WDCC_READ
Definition: ide_wdcreg.h:80
#define WDCC_IDLE
Definition: ide_wdcreg.h:104
#define WDCC_SETMULTI
Definition: ide_wdcreg.h:91
#define SET_FEATURES
Definition: ide_wdcreg.h:102
#define WDCC_READMULTI
Definition: ide_wdcreg.h:89
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 10, 5 > event
Bitfield< 54 > p
Definition: pagetable.hh:70
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
DevAction_t
Definition: ide_disk.hh:157
@ ACT_NONE
Definition: ide_disk.hh:158
@ ACT_CMD_ERROR
Definition: ide_disk.hh:161
@ ACT_DMA_DONE
Definition: ide_disk.hh:170
@ ACT_CMD_COMPLETE
Definition: ide_disk.hh:160
@ ACT_DMA_READY
Definition: ide_disk.hh:169
@ ACT_DATA_READY
Definition: ide_disk.hh:164
@ ACT_DATA_WRITE_BYTE
Definition: ide_disk.hh:167
@ ACT_SELECT_WRITE
Definition: ide_disk.hh:162
@ ACT_DATA_READ_BYTE
Definition: ide_disk.hh:165
@ ACT_SRST_SET
Definition: ide_disk.hh:171
@ ACT_CMD_WRITE
Definition: ide_disk.hh:159
@ ACT_SRST_CLEAR
Definition: ide_disk.hh:172
@ ACT_STAT_READ
Definition: ide_disk.hh:163
@ ACT_DATA_READ_SHORT
Definition: ide_disk.hh:166
@ ACT_DATA_WRITE_SHORT
Definition: ide_disk.hh:168
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
std::ostream CheckpointOut
Definition: serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
Definition: types.cc:40
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
Definition: types.cc:72
uint64_t Tick
Tick count type.
Definition: types.hh:58
Events_t
Definition: ide_disk.hh:146
@ DmaRead
Definition: ide_disk.hh:152
@ DmaWrite
Definition: ide_disk.hh:153
@ ReadWait
Definition: ide_disk.hh:149
@ PrdRead
Definition: ide_disk.hh:151
@ None
Definition: ide_disk.hh:147
@ WriteWait
Definition: ide_disk.hh:150
@ Transfer
Definition: ide_disk.hh:148
@ Device_Idle_NS
Definition: ide_disk.hh:180
@ Device_Dma_Abort
Definition: ide_disk.hh:201
@ Device_Idle_SI
Definition: ide_disk.hh:179
@ Data_Ready_INTRQ_Out
Definition: ide_disk.hh:195
@ Transfer_Data_Dma
Definition: ide_disk.hh:200
@ Device_Srst
Definition: ide_disk.hh:183
@ Prepare_Data_Out
Definition: ide_disk.hh:194
@ Prepare_Data_In
Definition: ide_disk.hh:189
@ Command_Execution
Definition: ide_disk.hh:186
@ Device_Idle_S
Definition: ide_disk.hh:178
@ Data_Ready_INTRQ_In
Definition: ide_disk.hh:190
@ Transfer_Data_Out
Definition: ide_disk.hh:196
@ Prepare_Data_Dma
Definition: ide_disk.hh:199
@ Transfer_Data_In
Definition: ide_disk.hh:191
@ Dma_Start
Definition: ide_disk.hh:207
@ Dma_Idle
Definition: ide_disk.hh:206
@ Dma_Transfer
Definition: ide_disk.hh:208
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
Simple PCI IDE controller with bus mastering capability and UDMA modeled after controller in the Inte...
statistics::Scalar dmaWriteTxs
Definition: ide_disk.hh:277
statistics::Scalar dmaWriteBytes
Definition: ide_disk.hh:276
IdeDiskStats(statistics::Group *parent)
Definition: ide_disk.cc:393
statistics::Scalar dmaWriteFullPages
Definition: ide_disk.hh:275
statistics::Scalar dmaReadBytes
Definition: ide_disk.hh:273
statistics::Scalar dmaReadFullPages
Definition: ide_disk.hh:272
statistics::Scalar dmaReadTxs
Definition: ide_disk.hh:274
uint16_t endOfTable
Definition: ide_disk.hh:76
uint32_t baseAddr
Definition: ide_disk.hh:74
uint16_t byteCount
Definition: ide_disk.hh:75
const std::string & name()
Definition: trace.cc:49

Generated on Wed Dec 21 2022 10:22:35 for gem5 by doxygen 1.9.1