gem5 [DEVELOP-FOR-25.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
44
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), dataBuffer(nullptr),
68 ideDiskStats(this),
69 dmaTransferEvent([this]{ doDmaTransfer(); }, name()),
70 dmaReadWaitEvent([this]{ doDmaRead(); }, name()),
71 dmaWriteWaitEvent([this]{ doDmaWrite(); }, name()),
72 dmaPrdReadEvent([this]{ dmaPrdReadDone(); }, name()),
73 dmaReadEvent([this]{ dmaReadDone(); }, name()),
74 dmaWriteEvent([this]{ dmaWriteDone(); }, name())
75{
76 // Reset the device state
77 reset(p.driveID);
78
79 // fill out the drive ID structure
80 memset(&driveID, 0, sizeof(struct ataparams));
81
82 // Calculate LBA and C/H/S values
83 uint16_t cylinders;
84 uint8_t heads;
85 uint8_t sectors;
86
87 uint32_t lba_size = image->size();
88 if (lba_size >= 16383*16*63) {
89 cylinders = 16383;
90 heads = 16;
91 sectors = 63;
92 } else {
93 if (lba_size >= 63)
94 sectors = 63;
95 else if (lba_size == 0)
96 panic("Bad IDE image size: 0\n");
97 else
98 sectors = lba_size;
99
100 if ((lba_size / sectors) >= 16)
101 heads = 16;
102 else
103 heads = (lba_size / sectors);
104
105 cylinders = lba_size / (heads * sectors);
106 }
107
108 // Setup the model name
109 strncpy((char *)driveID.atap_model, "5MI EDD si k",
110 sizeof(driveID.atap_model));
111 // Set the maximum multisector transfer size
112 driveID.atap_multi = MAX_MULTSECT;
113 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
114 driveID.atap_capabilities1 = 0x7;
115 // UDMA support, EIDE support
116 driveID.atap_extensions = 0x6;
117 // Setup default C/H/S settings
118 driveID.atap_cylinders = cylinders;
119 driveID.atap_sectors = sectors;
120 driveID.atap_heads = heads;
121 // Setup the current multisector transfer size
122 driveID.atap_curmulti = MAX_MULTSECT;
123 driveID.atap_curmulti_valid = 0x1;
124 // Number of sectors on disk
125 driveID.atap_capacity = lba_size;
126 // Multiword DMA mode 2 and below supported
127 driveID.atap_dmamode_supp = 0x4;
128 // Set PIO mode 4 and 3 supported
129 driveID.atap_piomode_supp = 0x3;
130 // Set DMA mode 4 and below supported
131 driveID.atap_udmamode_supp = 0x1f;
132 // Statically set hardware config word
133 driveID.atap_hwreset_res = 0x4001;
134
135 //arbitrary for now...
136 driveID.atap_ata_major = WDC_VER_ATA7;
137}
138
140{
141 // destroy the data buffer
142 delete [] dataBuffer;
143}
144
145void
147{
148 // initialize the data buffer and shadow registers
149 // if the data buffer has not been allocated yet
150 if (!dataBuffer)
151 dataBuffer = new uint8_t[MAX_DMA_SIZE];
152
153 memset(dataBuffer, 0, MAX_DMA_SIZE);
154 memset(&cmdReg, 0, sizeof(CommandReg_t));
155 memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
156
157 curPrdAddr = 0;
158 curSector = 0;
159 cmdBytes = 0;
160 cmdBytesLeft = 0;
161 drqBytesLeft = 0;
162 dmaRead = false;
163 pendingInterrupt = false;
164 dmaAborted = false;
165
166 // set the device state to idle
168
169 if (id == DEV0) {
171 devID = DEV0;
172 } else if (id == DEV1) {
174 devID = DEV1;
175 } else {
176 panic("Invalid device ID: %#x\n", id);
177 }
178
179 // set the device ready bit
181
182 /* The error register must be set to 0x1 on start-up to
183 indicate that no diagnostic error was detected */
184 cmdReg.error = 0x1;
185}
186
188// Utility functions
190
191bool
193{
194 return channel->selected() == this;
195}
196
197Addr
199{
200 panic_if(!ctrl, "Access to unset controller!");
201 return ctrl->pciToDma(pciAddr);
202}
203
205// Device registers read/write
207
208void
209IdeDisk::readCommand(const Addr offset, int size, uint8_t *data)
210{
211 if (offset == DATA_OFFSET) {
212 if (size == sizeof(uint16_t)) {
213 *(uint16_t *)data = cmdReg.data;
214 } else if (size == sizeof(uint32_t)) {
215 *(uint16_t *)data = cmdReg.data;
217 *((uint16_t *)data + 1) = cmdReg.data;
218 } else {
219 panic("Data read of unsupported size %d.\n", size);
220 }
222 return;
223 }
224 assert(size == sizeof(uint8_t));
225 switch (offset) {
226 case ERROR_OFFSET:
227 *data = cmdReg.error;
228 break;
229 case NSECTOR_OFFSET:
230 *data = cmdReg.sec_count;
231 break;
232 case SECTOR_OFFSET:
233 *data = cmdReg.sec_num;
234 break;
235 case LCYL_OFFSET:
236 *data = cmdReg.cyl_low;
237 break;
238 case HCYL_OFFSET:
239 *data = cmdReg.cyl_high;
240 break;
241 case DRIVE_OFFSET:
242 *data = cmdReg.drive;
243 break;
244 case STATUS_OFFSET:
245 *data = status;
247 break;
248 default:
249 panic("Invalid IDE command register offset: %#x\n", offset);
250 }
251 DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
252}
253
254void
255IdeDisk::readControl(const Addr offset, int size, uint8_t *data)
256{
257 assert(size == sizeof(uint8_t));
258 *data = status;
259 if (offset != ALTSTAT_OFFSET)
260 panic("Invalid IDE control register offset: %#x\n", offset);
261 DPRINTF(IdeDisk, "Read to disk at offset: %#x data %#x\n", offset, *data);
262}
263
264void
265IdeDisk::writeCommand(const Addr offset, int size, const uint8_t *data)
266{
267 if (offset == DATA_OFFSET) {
268 if (size == sizeof(uint16_t)) {
269 cmdReg.data = *(const uint16_t *)data;
270 } else if (size == sizeof(uint32_t)) {
271 cmdReg.data = *(const uint16_t *)data;
273 cmdReg.data = *((const uint16_t *)data + 1);
274 } else {
275 panic("Data write of unsupported size %d.\n", size);
276 }
278 return;
279 }
280
281 assert(size == sizeof(uint8_t));
282 switch (offset) {
283 case FEATURES_OFFSET:
284 break;
285 case NSECTOR_OFFSET:
286 cmdReg.sec_count = *data;
287 break;
288 case SECTOR_OFFSET:
289 cmdReg.sec_num = *data;
290 break;
291 case LCYL_OFFSET:
292 cmdReg.cyl_low = *data;
293 break;
294 case HCYL_OFFSET:
295 cmdReg.cyl_high = *data;
296 break;
297 case DRIVE_OFFSET:
298 cmdReg.drive = *data;
300 break;
301 case COMMAND_OFFSET:
302 cmdReg.command = *data;
304 break;
305 default:
306 panic("Invalid IDE command register offset: %#x\n", offset);
307 }
308 DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
309 (uint32_t)*data);
310}
311
312void
313IdeDisk::writeControl(const Addr offset, int size, const uint8_t *data)
314{
315 if (offset != CONTROL_OFFSET)
316 panic("Invalid IDE control register offset: %#x\n", offset);
317
318 if (*data & CONTROL_RST_BIT) {
319 // force the device into the reset state
322 } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT)) {
324 }
325
327
328 DPRINTF(IdeDisk, "Write to disk at offset: %#x data %#x\n", offset,
329 (uint32_t)*data);
330}
331
333// Perform DMA transactions
335
336void
338{
339 if (dmaAborted) {
340 DPRINTF(IdeDisk, "DMA Aborted before reading PRD entry\n");
342 return;
343 }
344
346 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
348 }
349
350 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
352 return;
353 } else {
354 ctrl->dmaRead(curPrdAddr, sizeof(PrdEntry_t), &dmaPrdReadEvent,
355 (uint8_t*)&curPrd.entry);
356 }
357}
358
359void
361{
362 if (dmaAborted) {
363 DPRINTF(IdeDisk, "DMA Aborted while reading PRD entry\n");
365 return;
366 }
367
369 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
370 curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
371 curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
372 curPrd.getEOT(), curSector);
373
374 // the prd pointer has already been translated, so just do an increment
375 curPrdAddr = curPrdAddr + sizeof(PrdEntry_t);
376
377 if (dmaRead)
379 else
381}
382
383void
385{
387 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
388
389 DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
390 diskDelay, totalDiskDelay);
391
392 schedule(dmaReadWaitEvent, curTick() + totalDiskDelay);
393}
394
397 : statistics::Group(parent, "IdeDisk"),
399 "Number of full page size DMA reads (not PRD)."),
400 ADD_STAT(dmaReadBytes, statistics::units::Byte::get(),
401 "Number of bytes transfered via DMA reads (not PRD)."),
402 ADD_STAT(dmaReadTxs, statistics::units::Count::get(),
403 "Number of DMA read transactions (not PRD)."),
405 "Number of full page size DMA writes."),
406 ADD_STAT(dmaWriteBytes, statistics::units::Byte::get(),
407 "Number of bytes transfered via DMA writes."),
408 ADD_STAT(dmaWriteTxs, statistics::units::Count::get(),
409 "Number of DMA write transactions.")
410{
411}
412
413void
415{
416 if (dmaAborted) {
417 DPRINTF(IdeDisk, "DMA Aborted in middle of Dma Read\n");
418 if (dmaReadCG)
419 delete dmaReadCG;
420 dmaReadCG = NULL;
422 return;
423 }
424
425 if (!dmaReadCG) {
426 // clear out the data buffer
427 memset(dataBuffer, 0, MAX_DMA_SIZE);
428 dmaReadCG = new ChunkGenerator(curPrd.getBaseAddr(),
429 curPrd.getByteCount(), chunkBytes);
430
431 }
432 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
434 return;
435 } else if (!dmaReadCG->done()) {
436 assert(dmaReadCG->complete() < MAX_DMA_SIZE);
437 ctrl->dmaRead(pciToDma(dmaReadCG->addr()), dmaReadCG->size(),
438 &dmaReadWaitEvent, dataBuffer + dmaReadCG->complete());
439 ideDiskStats.dmaReadBytes += dmaReadCG->size();
440 ideDiskStats.dmaReadTxs++;
441 if (dmaReadCG->size() == chunkBytes)
442 ideDiskStats.dmaReadFullPages++;
443 dmaReadCG->next();
444 } else {
445 assert(dmaReadCG->done());
446 delete dmaReadCG;
447 dmaReadCG = NULL;
448 dmaReadDone();
449 }
450}
451
452void
454{
455 uint32_t bytesWritten = 0;
456
457 // write the data to the disk image
458 for (bytesWritten = 0; bytesWritten < curPrd.getByteCount();
459 bytesWritten += SectorSize) {
460
462 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
463 }
464
465 // check for the EOT
466 if (curPrd.getEOT()) {
467 assert(cmdBytesLeft == 0);
470 } else {
472 }
473}
474
475void
477{
479 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
480 uint32_t bytesRead = 0;
481
482 DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
483 diskDelay, totalDiskDelay);
484
485 memset(dataBuffer, 0, MAX_DMA_SIZE);
486 assert(cmdBytesLeft <= MAX_DMA_SIZE);
487 while (bytesRead < curPrd.getByteCount()) {
488 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
489 bytesRead += SectorSize;
491 }
492 DPRINTF(IdeDisk, "doDmaWrite, bytesRead: %d cmdBytesLeft: %d\n",
493 bytesRead, cmdBytesLeft);
494
495 schedule(dmaWriteWaitEvent, curTick() + totalDiskDelay);
496}
497
498void
500{
501 if (dmaAborted) {
502 DPRINTF(IdeDisk, "DMA Aborted while doing DMA Write\n");
503 if (dmaWriteCG)
504 delete dmaWriteCG;
505 dmaWriteCG = NULL;
507 return;
508 }
509 if (!dmaWriteCG) {
510 // clear out the data buffer
511 dmaWriteCG = new ChunkGenerator(curPrd.getBaseAddr(),
512 curPrd.getByteCount(), chunkBytes);
513 }
514 if (ctrl->dmaPending() || ctrl->drainState() != DrainState::Running) {
516 DPRINTF(IdeDisk, "doDmaWrite: rescheduling\n");
517 return;
518 } else if (!dmaWriteCG->done()) {
519 assert(dmaWriteCG->complete() < MAX_DMA_SIZE);
520 ctrl->dmaWrite(pciToDma(dmaWriteCG->addr()), dmaWriteCG->size(),
521 &dmaWriteWaitEvent, dataBuffer + dmaWriteCG->complete());
522 DPRINTF(IdeDisk, "doDmaWrite: not done curPrd byte count %d, eot %#x\n",
523 curPrd.getByteCount(), curPrd.getEOT());
524 ideDiskStats.dmaWriteBytes += dmaWriteCG->size();
525 ideDiskStats.dmaWriteTxs++;
526 if (dmaWriteCG->size() == chunkBytes)
527 ideDiskStats.dmaWriteFullPages++;
528 dmaWriteCG->next();
529 } else {
530 DPRINTF(IdeDisk, "doDmaWrite: done curPrd byte count %d, eot %#x\n",
531 curPrd.getByteCount(), curPrd.getEOT());
532 assert(dmaWriteCG->done());
533 delete dmaWriteCG;
534 dmaWriteCG = NULL;
535 dmaWriteDone();
536 }
537}
538
539void
541{
543 "doWriteDone: curPrd byte count %d, eot %#x cmd bytes left:%d\n",
544 curPrd.getByteCount(), curPrd.getEOT(), cmdBytesLeft);
545 // check for the EOT
546 if (curPrd.getEOT()) {
547 assert(cmdBytesLeft == 0);
550 } else {
552 }
553}
554
556// Disk utility routines
558
559void
560IdeDisk::readDisk(uint32_t sector, uint8_t *data)
561{
562 uint32_t bytesRead = image->read(data, sector);
563
564 panic_if(bytesRead != SectorSize,
565 "Can't read from %s. Only %d of %d read. errno=%d",
566 name(), bytesRead, SectorSize, errno);
567}
568
569void
570IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
571{
572 uint32_t bytesWritten = image->write(data, sector);
573
574 panic_if(bytesWritten != SectorSize,
575 "Can't write to %s. Only %d of %d written. errno=%d",
576 name(), bytesWritten, SectorSize, errno);
577}
578
580// Setup and handle commands
582
583void
584IdeDisk::startDma(const uint32_t &prdTableBase)
585{
587 "Inconsistent DMA state, should be in Dma_Start!");
588
590 "Inconsistent device state for DMA start!");
591
592 // PRD base address is given by bits 31:2
593 curPrdAddr = pciToDma((Addr)(prdTableBase & ~0x3ULL));
594
596
597 // schedule dma transfer (doDmaTransfer)
599}
600
601void
603{
605 "Inconsistent DMA state, should be Start or Transfer!");
606
608 "Inconsistent device state, should be Transfer or Prepare!");
609
611}
612
613void
615{
616 DevAction_t action = ACT_NONE;
617 uint32_t size = 0;
618 dmaRead = false;
619
620 // Clear any existing errors.
621 replaceBits(status, 0, 0);
622 replaceBits(cmdReg.error, 2, 0);
623
624 // Decode commands
625 switch (cmdReg.command) {
626 // Supported non-data commands
628 size = (uint32_t)image->size() - 1;
629 cmdReg.sec_num = (size & 0xff);
630 cmdReg.cyl_low = ((size & 0xff00) >> 8);
631 cmdReg.cyl_high = ((size & 0xff0000) >> 16);
632 cmdReg.head = ((size & 0xf000000) >> 24);
633
635 action = ACT_CMD_COMPLETE;
636 break;
637
638 case WDCC_RECAL:
639 case WDCC_IDP:
641 case WDCC_FLUSHCACHE:
642 case WDSF_VERIFY:
643 case WDSF_SEEK:
644 case SET_FEATURES:
645 case WDCC_SETMULTI:
646 case WDCC_IDLE:
648 action = ACT_CMD_COMPLETE;
649 break;
650
651 // Supported PIO data-in commands
652 case WDCC_IDENTIFY:
653 cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
655 action = ACT_DATA_READY;
656 break;
657
659 // We're not an ATAPI device, so this command isn't implemented.
661 action = ACT_CMD_ERROR;
662 replaceBits(cmdReg.error, 2, 1);
663 replaceBits(status, 0, 1);
664 break;
665
666 case WDCC_READMULTI:
667 case WDCC_READ:
668 panic_if(!(cmdReg.drive & DRIVE_LBA_BIT),
669 "Attempt to perform CHS access, only supports LBA");
670
671 if (cmdReg.sec_count == 0)
672 cmdBytes = cmdBytesLeft = (256 * SectorSize);
673 else
674 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
675
677
680 action = ACT_DATA_READY;
681 break;
682
683 // Supported PIO data-out commands
684 case WDCC_WRITEMULTI:
685 case WDCC_WRITE:
686 panic_if(!(cmdReg.drive & DRIVE_LBA_BIT),
687 "Attempt to perform CHS access, only supports LBA");
688
689 if (cmdReg.sec_count == 0)
690 cmdBytes = cmdBytesLeft = (256 * SectorSize);
691 else
692 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
693 DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d\n", cmdBytesLeft);
695
697 action = ACT_DATA_READY;
698 break;
699
700 // Supported DMA commands
701 case WDCC_WRITEDMA:
702 dmaRead = true; // a write to the disk is a DMA read from memory
703 [[fallthrough]];
704 case WDCC_READDMA:
705 panic_if(!(cmdReg.drive & DRIVE_LBA_BIT),
706 "Attempt to perform CHS access, only supports LBA");
707
708 if (cmdReg.sec_count == 0)
709 cmdBytes = cmdBytesLeft = (256 * SectorSize);
710 else
711 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
712 DPRINTF(IdeDisk, "Setting cmdBytesLeft to %d in readdma\n",
714
716
718 action = ACT_DMA_READY;
719 break;
720
721 default:
722 panic("Unsupported ATA command: %#x\n", cmdReg.command);
723 }
724
725 if (action != ACT_NONE) {
726 // set the BSY bit
728 // clear the DRQ bit
730 // clear the DF bit
732
733 updateState(action);
734 }
735}
736
738// Handle setting and clearing interrupts
740
741void
743{
744 DPRINTF(IdeDisk, "Posting Interrupt\n");
746 "Attempt to post an interrupt with one pending");
747
748 pendingInterrupt = true;
749
750 assert(channel);
751 channel->postInterrupt();
752}
753
754void
756{
757 DPRINTF(IdeDisk, "Clearing Interrupt\n");
758 panic_if(!pendingInterrupt, "Attempt to clear a non-pending interrupt");
759
760 pendingInterrupt = false;
761
762 assert(channel);
763 channel->clearInterrupt();
764}
765
767// Manage the device internal state machine
769
770void
772{
773 switch (devState) {
774 case Device_Srst:
775 if (action == ACT_SRST_SET) {
776 // set the BSY bit
778 } else if (action == ACT_SRST_CLEAR) {
779 // clear the BSY bit
781
782 // reset the device state
783 reset(devID);
784 }
785 break;
786
787 case Device_Idle_S:
788 if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
790 } else if (action == ACT_CMD_WRITE) {
791 startCommand();
792 }
793
794 break;
795
796 case Device_Idle_SI:
797 if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
800 } else if (action == ACT_STAT_READ || isIENSet()) {
803 } else if (action == ACT_CMD_WRITE) {
805 startCommand();
806 }
807
808 break;
809
810 case Device_Idle_NS:
811 if (action == ACT_SELECT_WRITE && isDEVSelect()) {
812 if (!isIENSet() && pendingInterrupt) {
815 }
816 if (isIENSet() || !pendingInterrupt) {
818 }
819 }
820 break;
821
823 if (action == ACT_CMD_ERROR || action == ACT_CMD_COMPLETE) {
824 // clear the BSY bit
825 setComplete();
826
827 if (!isIENSet()) {
830 } else {
832 }
833 }
834 break;
835
836 case Prepare_Data_In:
837 if (action == ACT_CMD_ERROR) {
838 // clear the BSY bit
839 setComplete();
840
841 if (!isIENSet()) {
844 } else {
846 }
847 } else if (action == ACT_DATA_READY) {
848 // clear the BSY bit
850 // set the DRQ bit
852
853 // copy the data into the data buffer
854 if (cmdReg.command == WDCC_IDENTIFY ||
855 cmdReg.command == ATAPI_IDENTIFY_DEVICE) {
856 // Reset the drqBytes for this block
857 drqBytesLeft = sizeof(struct ataparams);
858
859 memcpy((void *)dataBuffer, (void *)&driveID,
860 sizeof(struct ataparams));
861 } else {
862 // Reset the drqBytes for this block
864
866 }
867
868 // put the first two bytes into the data register
869 memcpy((void *)&cmdReg.data, (void *)dataBuffer,
870 sizeof(uint16_t));
871
872 if (!isIENSet()) {
875 } else {
877 }
878 }
879 break;
880
882 if (action == ACT_STAT_READ) {
885 }
886 break;
887
888 case Transfer_Data_In:
889 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
890 if (action == ACT_DATA_READ_BYTE) {
891 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
892 } else {
893 drqBytesLeft -= 2;
894 cmdBytesLeft -= 2;
895
896 // copy next short into data registers
897 if (drqBytesLeft)
898 memcpy((void *)&cmdReg.data,
900 sizeof(uint16_t));
901 }
902
903 if (drqBytesLeft == 0) {
904 if (cmdBytesLeft == 0) {
905 // Clear the BSY bit
906 setComplete();
908 } else {
910 // set the BSY_BIT
912 // clear the DRQ_BIT
914
918 }
919 }
920 }
921 break;
922
923 case Prepare_Data_Out:
924 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
925 // clear the BSY bit
926 setComplete();
927
928 if (!isIENSet()) {
931 } else {
933 }
934 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
935 // clear the BSY bit
937 // set the DRQ bit
939
940 // clear the data buffer to get it ready for writes
941 memset(dataBuffer, 0, MAX_DMA_SIZE);
942
943 // reset the drqBytes for this block
945
946 if (cmdBytesLeft == cmdBytes || isIENSet()) {
948 } else {
951 }
952 }
953 break;
954
956 if (action == ACT_STAT_READ) {
959 }
960 break;
961
963 if (action == ACT_DATA_WRITE_BYTE ||
964 action == ACT_DATA_WRITE_SHORT) {
965
966 if (action == ACT_DATA_READ_BYTE) {
967 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
968 } else {
969 // copy the latest short into the data buffer
970 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
971 (void *)&cmdReg.data,
972 sizeof(uint16_t));
973
974 drqBytesLeft -= 2;
975 cmdBytesLeft -= 2;
976 }
977
978 if (drqBytesLeft == 0) {
979 // copy the block to the disk
981
982 // set the BSY bit
984 // set the seek bit
986 // clear the DRQ bit
988
990
994 }
995 }
996 break;
997
998 case Prepare_Data_Dma:
999 if (action == ACT_CMD_ERROR) {
1000 // clear the BSY bit
1001 setComplete();
1002
1003 if (!isIENSet()) {
1005 postInterrupt();
1006 } else {
1008 }
1009 } else if (action == ACT_DMA_READY) {
1010 // clear the BSY bit
1012 // set the DRQ bit
1014
1016
1017 if (dmaState != Dma_Idle)
1018 panic("Inconsistent DMA state, should be Dma_Idle\n");
1019
1021 // wait for the write to the DMA start bit
1022 }
1023 break;
1024
1025 case Transfer_Data_Dma:
1026 if (action == ACT_CMD_ERROR) {
1027 dmaAborted = true;
1029 } else if (action == ACT_DMA_DONE) {
1030 // clear the BSY bit
1031 setComplete();
1032 // set the seek bit
1034 // clear the controller state for DMA transfer
1035 channel->setDmaComplete();
1036
1037 if (!isIENSet()) {
1039 postInterrupt();
1040 } else {
1042 }
1043 }
1044 break;
1045
1046 case Device_Dma_Abort:
1047 if (action == ACT_CMD_ERROR) {
1048 setComplete();
1050 channel->setDmaComplete();
1051 dmaAborted = false;
1053
1054 if (!isIENSet()) {
1056 postInterrupt();
1057 } else {
1059 }
1060 } else {
1061 DPRINTF(IdeDisk, "Disk still busy aborting previous DMA command\n");
1062 }
1063 break;
1064
1065 default:
1066 panic("Unknown IDE device state: %#x\n", devState);
1067 }
1068}
1069
1070void
1072{
1073 // Check all outstanding events to see if they are scheduled
1074 // these are all mutually exclusive
1075 Tick reschedule = 0;
1076 Events_t event = None;
1077
1078 [[maybe_unused]] int eventCount = 0;
1079
1080 if (dmaTransferEvent.scheduled()) {
1082 event = Transfer;
1083 eventCount++;
1084 }
1085 if (dmaReadWaitEvent.scheduled()) {
1087 event = ReadWait;
1088 eventCount++;
1089 }
1090 if (dmaWriteWaitEvent.scheduled()) {
1092 event = WriteWait;
1093 eventCount++;
1094 }
1095 if (dmaPrdReadEvent.scheduled()) {
1096 reschedule = dmaPrdReadEvent.when();
1097 event = PrdRead;
1098 eventCount++;
1099 }
1100 if (dmaReadEvent.scheduled()) {
1101 reschedule = dmaReadEvent.when();
1102 event = DmaRead;
1103 eventCount++;
1104 }
1105 if (dmaWriteEvent.scheduled()) {
1106 reschedule = dmaWriteEvent.when();
1107 event = DmaWrite;
1108 eventCount++;
1109 }
1110
1111 assert(eventCount <= 1);
1112
1115
1116 // Serialize device registers
1118 SERIALIZE_SCALAR(cmdReg.sec_count);
1119 SERIALIZE_SCALAR(cmdReg.sec_num);
1120 SERIALIZE_SCALAR(cmdReg.cyl_low);
1121 SERIALIZE_SCALAR(cmdReg.cyl_high);
1122 SERIALIZE_SCALAR(cmdReg.drive);
1123 SERIALIZE_SCALAR(cmdReg.command);
1127
1128 // Serialize the PRD related information
1129 SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1130 SERIALIZE_SCALAR(curPrd.entry.byteCount);
1131 SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1133
1135 // Serialize current transfer related information
1141 paramOut(cp, "intrPending", pendingInterrupt);
1146}
1147
1148void
1150{
1151 // Reschedule events that were outstanding
1152 // these are all mutually exclusive
1153 Tick reschedule = 0;
1154 Events_t event = None;
1155
1158
1159 switch (event) {
1160 case None : break;
1165 case DmaRead : schedule(dmaReadEvent, reschedule); break;
1166 case DmaWrite : schedule(dmaWriteEvent, reschedule); break;
1167 }
1168
1169 // Unserialize device registers
1171 UNSERIALIZE_SCALAR(cmdReg.sec_count);
1172 UNSERIALIZE_SCALAR(cmdReg.sec_num);
1173 UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1174 UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1176 UNSERIALIZE_SCALAR(cmdReg.command);
1180
1181 // Unserialize the PRD related information
1182 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1183 UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1184 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1186
1188 // Unserialize current transfer related information
1194 paramIn(cp, "intrPending", pendingInterrupt);
1199}
1200
1201} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
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...
EventFunctionWrapper dmaReadEvent
Definition ide_disk.hh:344
void startCommand()
Definition ide_disk.cc:614
uint32_t drqBytesLeft
Number of bytes left in DRQ block.
Definition ide_disk.hh:240
void dmaReadDone()
Definition ide_disk.cc:453
void doDmaTransfer()
Definition ide_disk.cc:337
EventFunctionWrapper dmaPrdReadEvent
Definition ide_disk.hh:341
void doDmaDataRead()
Definition ide_disk.cc:384
void startDma(const uint32_t &prdTableBase)
Definition ide_disk.cc:584
void doDmaDataWrite()
Definition ide_disk.cc:476
void abortDma()
Definition ide_disk.cc:602
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition ide_disk.cc:1071
~IdeDisk()
Delete the data buffer.
Definition ide_disk.cc:139
void writeDisk(uint32_t sector, uint8_t *data)
Definition ide_disk.cc:570
bool isDEVSelect()
Definition ide_disk.cc:192
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:255
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:265
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:755
void dmaPrdReadDone()
Definition ide_disk.cc:360
struct ataparams driveID
Drive identification structure for this disk.
Definition ide_disk.hh:232
void postInterrupt()
Definition ide_disk.cc:742
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:1149
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:414
EventFunctionWrapper dmaWriteWaitEvent
Definition ide_disk.hh:338
void doDmaWrite()
Definition ide_disk.cc:499
void reset(int id)
Reset the device state.
Definition ide_disk.cc:146
gem5::IdeDisk::IdeDiskStats ideDiskStats
ChunkGenerator * dmaReadCG
Definition ide_disk.hh:331
void readDisk(uint32_t sector, uint8_t *data)
Definition ide_disk.cc:560
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:313
bool dmaAborted
DMA Aborted.
Definition ide_disk.hh:266
void dmaWriteDone()
Definition ide_disk.cc:540
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:198
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:209
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:771
uint32_t getLBABase()
Definition ide_disk.hh:373
virtual std::string name() const
Definition named.hh:60
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
@ Running
Running normally.
Definition drain.hh:76
void schedule(Event &event, Tick when)
Definition eventq.hh:1012
void reschedule(Event &event, Tick when, bool always=false)
Definition eventq.hh:1030
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:246
#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
SimObject(const Params &p)
Definition sim_object.cc:58
#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< 0 > p
Units for Stats.
Definition units.hh:113
Copyright (c) 2024 Arm Limited 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:396
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
const std::string & name()
Definition trace.cc:48

Generated on Mon May 26 2025 09:19:10 for gem5 by doxygen 1.13.2