gem5 v24.0.0.0
Loading...
Searching...
No Matches
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
46
47#include <cerrno>
48#include <cstring>
49#include <deque>
50#include <string>
51
52#include "base/bitfield.hh"
54#include "base/compiler.hh"
55#include "base/cprintf.hh" // csprintf
56#include "base/trace.hh"
57#include "debug/IdeDisk.hh"
60#include "sim/cur_tick.hh"
61#include "sim/sim_object.hh"
62
63namespace 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
144void
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
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
188bool
190{
191 return channel->selected() == this;
192}
193
194Addr
196{
197 panic_if(!ctrl, "Access to unset controller!");
198 return ctrl->pciToDma(pciAddr);
199}
200
202// Device registers read/write
204
205void
206IdeDisk::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:
228 break;
229 case SECTOR_OFFSET:
231 break;
232 case LCYL_OFFSET:
234 break;
235 case HCYL_OFFSET:
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
251void
252IdeDisk::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
261void
262IdeDisk::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:
284 break;
285 case SECTOR_OFFSET:
287 break;
288 case LCYL_OFFSET:
290 break;
291 case HCYL_OFFSET:
293 break;
294 case DRIVE_OFFSET:
295 cmdReg.drive = *data;
297 break;
298 case COMMAND_OFFSET:
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
309void
310IdeDisk::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
333void
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",
345 }
346
349 return;
350 } else {
352 (uint8_t*)&curPrd.entry);
353 }
354}
355
356void
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",
370
371 // the prd pointer has already been translated, so just do an increment
372 curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
373
374 if (dmaRead)
376 else
378}
379
380void
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
410void
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
449void
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);
467 } else {
469 }
470}
471
472void
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
495void
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
536void
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);
547 } else {
549 }
550}
551
553// Disk utility routines
555
556void
557IdeDisk::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
566void
567IdeDisk::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
580void
581IdeDisk::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
598void
600{
602 "Inconsistent DMA state, should be Start or Transfer!");
603
605 "Inconsistent device state, should be Transfer or Prepare!");
606
608}
609
610void
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:
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
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);
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",
711
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
726 status &= ~STATUS_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
738void
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
751void
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
767void
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
777 status &= ~STATUS_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()) {
797 } else if (action == ACT_STAT_READ || isIENSet()) {
800 } else if (action == ACT_CMD_WRITE) {
802 startCommand();
803 }
804
805 break;
806
807 case Device_Idle_NS:
808 if (action == ACT_SELECT_WRITE && isDEVSelect()) {
809 if (!isIENSet() && pendingInterrupt) {
812 }
813 if (isIENSet() || !pendingInterrupt) {
815 }
816 }
817 break;
818
820 if (action == ACT_CMD_ERROR || action == ACT_CMD_COMPLETE) {
821 // clear the BSY bit
822 setComplete();
823
824 if (!isIENSet()) {
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()) {
841 } else {
843 }
844 } else if (action == ACT_DATA_READY) {
845 // clear the BSY bit
846 status &= ~STATUS_BSY_BIT;
847 // set the DRQ bit
849
850 // copy the data into the data buffer
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()) {
872 } else {
874 }
875 }
876 break;
877
879 if (action == ACT_STAT_READ) {
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,
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
910 status &= ~STATUS_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()) {
928 } else {
930 }
931 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
932 // clear the BSY bit
933 status &= ~STATUS_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 {
948 }
949 }
950 break;
951
953 if (action == ACT_STAT_READ) {
956 }
957 break;
958
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
984 status &= ~STATUS_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
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;
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
1067void
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 [[maybe_unused]] int eventCount = 0;
1076
1079 event = Transfer;
1080 eventCount++;
1081 }
1084 event = ReadWait;
1085 eventCount++;
1086 }
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
1145void
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;
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:210
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)
bool dmaPending() const
void dmaRead(Addr addr, int size, Event *event, uint8_t *data, uint32_t sid, uint32_t ssid, Tick delay=0)
IdeDisk * selected() const
Definition ide_ctrl.hh:135
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.
Statistics container.
Definition group.hh:93
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:216
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:458
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
void reschedule(Event &event, Tick when, bool always=false)
Definition eventq.hh:1030
Tick when() const
Get the time that the event is scheduled.
Definition eventq.hh:501
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:188
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
#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 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< 0 > p
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
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
@ 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:48

Generated on Tue Jun 18 2024 16:24:03 for gem5 by doxygen 1.11.0