Use functions to access XC.
[gem5.git] / dev / ide_disk.cc
1 /*
2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met: redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer;
9 * redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution;
12 * neither the name of the copyright holders nor the names of its
13 * contributors may be used to endorse or promote products derived from
14 * this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /** @file
30 * Device model implementation for an IDE disk
31 */
32
33 #include <cerrno>
34 #include <cstring>
35 #include <deque>
36 #include <string>
37
38 #include "base/cprintf.hh" // csprintf
39 #include "base/trace.hh"
40 #include "dev/disk_image.hh"
41 #include "dev/ide_disk.hh"
42 #include "dev/ide_ctrl.hh"
43 #include "dev/tsunami.hh"
44 #include "dev/tsunami_pchip.hh"
45 #include "mem/functional/physical.hh"
46 #include "mem/bus/bus.hh"
47 #include "mem/bus/dma_interface.hh"
48 #include "mem/bus/pio_interface.hh"
49 #include "mem/bus/pio_interface_impl.hh"
50 #include "sim/builder.hh"
51 #include "sim/sim_object.hh"
52 #include "sim/root.hh"
53 #include "arch/isa_traits.hh"
54
55 using namespace std;
56 using namespace TheISA;
57
58 IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys,
59 int id, Tick delay)
60 : SimObject(name), ctrl(NULL), image(img), physmem(phys), diskDelay(delay),
61 dmaTransferEvent(this), dmaReadWaitEvent(this),
62 dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
63 dmaReadEvent(this), dmaWriteEvent(this)
64 {
65 // Reset the device state
66 reset(id);
67
68 // fill out the drive ID structure
69 memset(&driveID, 0, sizeof(struct ataparams));
70
71 // Calculate LBA and C/H/S values
72 uint16_t cylinders;
73 uint8_t heads;
74 uint8_t sectors;
75
76 uint32_t lba_size = image->size();
77 if (lba_size >= 16383*16*63) {
78 cylinders = 16383;
79 heads = 16;
80 sectors = 63;
81 } else {
82 if (lba_size >= 63)
83 sectors = 63;
84 else
85 sectors = lba_size;
86
87 if ((lba_size / sectors) >= 16)
88 heads = 16;
89 else
90 heads = (lba_size / sectors);
91
92 cylinders = lba_size / (heads * sectors);
93 }
94
95 // Setup the model name
96 strncpy((char *)driveID.atap_model, "5MI EDD si k",
97 sizeof(driveID.atap_model));
98 // Set the maximum multisector transfer size
99 driveID.atap_multi = MAX_MULTSECT;
100 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
101 driveID.atap_capabilities1 = 0x7;
102 // UDMA support, EIDE support
103 driveID.atap_extensions = 0x6;
104 // Setup default C/H/S settings
105 driveID.atap_cylinders = cylinders;
106 driveID.atap_sectors = sectors;
107 driveID.atap_heads = heads;
108 // Setup the current multisector transfer size
109 driveID.atap_curmulti = MAX_MULTSECT;
110 driveID.atap_curmulti_valid = 0x1;
111 // Number of sectors on disk
112 driveID.atap_capacity = lba_size;
113 // Multiword DMA mode 2 and below supported
114 driveID.atap_dmamode_supp = 0x400;
115 // Set PIO mode 4 and 3 supported
116 driveID.atap_piomode_supp = 0x3;
117 // Set DMA mode 4 and below supported
118 driveID.atap_udmamode_supp = 0x1f;
119 // Statically set hardware config word
120 driveID.atap_hwreset_res = 0x4001;
121
122 //arbitrary for now...
123 driveID.atap_ata_major = WDC_VER_ATA7;
124 }
125
126 IdeDisk::~IdeDisk()
127 {
128 // destroy the data buffer
129 delete [] dataBuffer;
130 }
131
132 void
133 IdeDisk::reset(int id)
134 {
135 // initialize the data buffer and shadow registers
136 dataBuffer = new uint8_t[MAX_DMA_SIZE];
137
138 memset(dataBuffer, 0, MAX_DMA_SIZE);
139 memset(&cmdReg, 0, sizeof(CommandReg_t));
140 memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
141
142 dmaInterfaceBytes = 0;
143 curPrdAddr = 0;
144 curSector = 0;
145 cmdBytes = 0;
146 cmdBytesLeft = 0;
147 drqBytesLeft = 0;
148 dmaRead = false;
149 intrPending = false;
150
151 // set the device state to idle
152 dmaState = Dma_Idle;
153
154 if (id == DEV0) {
155 devState = Device_Idle_S;
156 devID = DEV0;
157 } else if (id == DEV1) {
158 devState = Device_Idle_NS;
159 devID = DEV1;
160 } else {
161 panic("Invalid device ID: %#x\n", id);
162 }
163
164 // set the device ready bit
165 status = STATUS_DRDY_BIT;
166
167 /* The error register must be set to 0x1 on start-up to
168 indicate that no diagnostic error was detected */
169 cmdReg.error = 0x1;
170 }
171
172 ////
173 // Utility functions
174 ////
175
176 bool
177 IdeDisk::isDEVSelect()
178 {
179 return ctrl->isDiskSelected(this);
180 }
181
182 Addr
183 IdeDisk::pciToDma(Addr pciAddr)
184 {
185 if (ctrl)
186 return ctrl->plat->pciToDma(pciAddr);
187 else
188 panic("Access to unset controller!\n");
189 }
190
191 uint32_t
192 IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft)
193 {
194 uint32_t bytesInPage = 0;
195
196 // First calculate how many bytes could be in the page
197 if (bytesLeft > TheISA::PageBytes)
198 bytesInPage = TheISA::PageBytes;
199 else
200 bytesInPage = bytesLeft;
201
202 // Next, see if we have crossed a page boundary, and adjust
203 Addr upperBound = curAddr + bytesInPage;
204 Addr pageBound = TheISA::TruncPage(curAddr) + TheISA::PageBytes;
205
206 assert(upperBound >= curAddr && "DMA read wraps around address space!\n");
207
208 if (upperBound >= pageBound)
209 bytesInPage = pageBound - curAddr;
210
211 return bytesInPage;
212 }
213
214 ////
215 // Device registers read/write
216 ////
217
218 void
219 IdeDisk::read(const Addr &offset, IdeRegType reg_type, uint8_t *data)
220 {
221 DevAction_t action = ACT_NONE;
222
223 switch (reg_type) {
224 case COMMAND_BLOCK:
225 switch (offset) {
226 // Data transfers occur two bytes at a time
227 case DATA_OFFSET:
228 *(uint16_t*)data = cmdReg.data;
229 action = ACT_DATA_READ_SHORT;
230 break;
231 case ERROR_OFFSET:
232 *data = cmdReg.error;
233 break;
234 case NSECTOR_OFFSET:
235 *data = cmdReg.sec_count;
236 break;
237 case SECTOR_OFFSET:
238 *data = cmdReg.sec_num;
239 break;
240 case LCYL_OFFSET:
241 *data = cmdReg.cyl_low;
242 break;
243 case HCYL_OFFSET:
244 *data = cmdReg.cyl_high;
245 break;
246 case DRIVE_OFFSET:
247 *data = cmdReg.drive;
248 break;
249 case STATUS_OFFSET:
250 *data = status;
251 action = ACT_STAT_READ;
252 break;
253 default:
254 panic("Invalid IDE command register offset: %#x\n", offset);
255 }
256 break;
257 case CONTROL_BLOCK:
258 if (offset == ALTSTAT_OFFSET)
259 *data = status;
260 else
261 panic("Invalid IDE control register offset: %#x\n", offset);
262 break;
263 default:
264 panic("Unknown register block!\n");
265 }
266
267 if (action != ACT_NONE)
268 updateState(action);
269 }
270
271 void
272 IdeDisk::write(const Addr &offset, IdeRegType reg_type, const uint8_t *data)
273 {
274 DevAction_t action = ACT_NONE;
275
276 switch (reg_type) {
277 case COMMAND_BLOCK:
278 switch (offset) {
279 case DATA_OFFSET:
280 cmdReg.data = *(uint16_t*)data;
281 action = ACT_DATA_WRITE_SHORT;
282 break;
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;
299 action = ACT_SELECT_WRITE;
300 break;
301 case COMMAND_OFFSET:
302 cmdReg.command = *data;
303 action = ACT_CMD_WRITE;
304 break;
305 default:
306 panic("Invalid IDE command register offset: %#x\n", offset);
307 }
308 break;
309 case CONTROL_BLOCK:
310 if (offset == CONTROL_OFFSET) {
311 if (*data & CONTROL_RST_BIT) {
312 // force the device into the reset state
313 devState = Device_Srst;
314 action = ACT_SRST_SET;
315 } else if (devState == Device_Srst && !(*data & CONTROL_RST_BIT))
316 action = ACT_SRST_CLEAR;
317
318 nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
319 }
320 else
321 panic("Invalid IDE control register offset: %#x\n", offset);
322 break;
323 default:
324 panic("Unknown register block!\n");
325 }
326
327 if (action != ACT_NONE)
328 updateState(action);
329 }
330
331 ////
332 // Perform DMA transactions
333 ////
334
335 void
336 IdeDisk::doDmaTransfer()
337 {
338 if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
339 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
340 dmaState, devState);
341
342 // first read the current PRD
343 if (dmaInterface) {
344 if (dmaInterface->busy()) {
345 // reschedule after waiting period
346 dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
347 return;
348 }
349
350 dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick,
351 &dmaPrdReadEvent);
352 } else {
353 dmaPrdReadDone();
354 }
355 }
356
357 void
358 IdeDisk::dmaPrdReadDone()
359 {
360 // actually copy the PRD from physical memory
361 memcpy((void *)&curPrd.entry,
362 physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)),
363 sizeof(PrdEntry_t));
364
365 DPRINTF(IdeDisk,
366 "PRD: baseAddr:%#x (%#x) byteCount:%d (%d) eot:%#x sector:%d\n",
367 curPrd.getBaseAddr(), pciToDma(curPrd.getBaseAddr()),
368 curPrd.getByteCount(), (cmdBytesLeft/SectorSize),
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 doDmaRead();
376 else
377 doDmaWrite();
378 }
379
380 void
381 IdeDisk::doDmaRead()
382 {
383 /** @todo we need to figure out what the delay actually will be */
384 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
385
386 DPRINTF(IdeDisk, "doDmaRead, diskDelay: %d totalDiskDelay: %d\n",
387 diskDelay, totalDiskDelay);
388 if (dmaInterface) {
389 if (dmaInterface->busy()) {
390 // reschedule after waiting period
391 dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
392 return;
393 }
394
395 Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
396
397 uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
398 (uint32_t)curPrd.getByteCount());
399
400 dmaInterfaceBytes = bytesInPage;
401
402 dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
403 curTick + totalDiskDelay, &dmaReadEvent);
404 } else {
405 // schedule dmaReadEvent with sectorDelay (dmaReadDone)
406 dmaReadEvent.schedule(curTick + totalDiskDelay);
407 }
408 }
409
410 void
411 IdeDisk::dmaReadDone()
412 {
413
414 Addr curAddr = 0, dmaAddr = 0;
415 uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0;
416
417 // continue to use the DMA interface until all pages are read
418 if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
419 // see if the interface is busy
420 if (dmaInterface->busy()) {
421 // reschedule after waiting period
422 dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
423 return;
424 }
425
426 uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
427 curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
428 dmaAddr = pciToDma(curAddr);
429
430 bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
431 dmaInterfaceBytes += bytesInPage;
432
433 dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
434 curTick, &dmaReadEvent);
435
436 return;
437 }
438
439 // set initial address
440 curAddr = curPrd.getBaseAddr();
441
442 // clear out the data buffer
443 memset(dataBuffer, 0, MAX_DMA_SIZE);
444
445 // read the data from memory via DMA into a data buffer
446 while (bytesWritten < curPrd.getByteCount()) {
447 if (cmdBytesLeft <= 0)
448 panic("DMA data is larger than # of sectors specified\n");
449
450 dmaAddr = pciToDma(curAddr);
451
452 // calculate how many bytes are in the current page
453 bytesLeft = curPrd.getByteCount() - bytesWritten;
454 bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
455
456 // copy the data from memory into the data buffer
457 memcpy((void *)(dataBuffer + bytesWritten),
458 physmem->dma_addr(dmaAddr, bytesInPage),
459 bytesInPage);
460
461 curAddr += bytesInPage;
462 bytesWritten += bytesInPage;
463 cmdBytesLeft -= bytesInPage;
464 }
465
466 // write the data to the disk image
467 for (bytesWritten = 0;
468 bytesWritten < curPrd.getByteCount();
469 bytesWritten += SectorSize) {
470
471 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
472 }
473
474 // check for the EOT
475 if (curPrd.getEOT()) {
476 assert(cmdBytesLeft == 0);
477 dmaState = Dma_Idle;
478 updateState(ACT_DMA_DONE);
479 } else {
480 doDmaTransfer();
481 }
482 }
483
484 void
485 IdeDisk::doDmaWrite()
486 {
487 /** @todo we need to figure out what the delay actually will be */
488 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
489
490 DPRINTF(IdeDisk, "doDmaWrite, diskDelay: %d totalDiskDelay: %d\n",
491 diskDelay, totalDiskDelay);
492
493 if (dmaInterface) {
494 if (dmaInterface->busy()) {
495 // reschedule after waiting period
496 dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
497 return;
498 }
499
500 Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
501
502 uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
503 (uint32_t)curPrd.getByteCount());
504
505 dmaInterfaceBytes = bytesInPage;
506
507 dmaInterface->doDMA(WriteInvalidate, dmaAddr,
508 bytesInPage, curTick + totalDiskDelay,
509 &dmaWriteEvent);
510 } else {
511 // schedule event with disk delay (dmaWriteDone)
512 dmaWriteEvent.schedule(curTick + totalDiskDelay);
513 }
514 }
515
516 void
517 IdeDisk::dmaWriteDone()
518 {
519 Addr curAddr = 0, pageAddr = 0, dmaAddr = 0;
520 uint32_t bytesRead = 0, bytesInPage = 0;
521
522 // continue to use the DMA interface until all pages are read
523 if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
524 // see if the interface is busy
525 if (dmaInterface->busy()) {
526 // reschedule after waiting period
527 dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
528 return;
529 }
530
531 uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
532 curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
533 dmaAddr = pciToDma(curAddr);
534
535 bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
536 dmaInterfaceBytes += bytesInPage;
537
538 dmaInterface->doDMA(WriteInvalidate, dmaAddr,
539 bytesInPage, curTick,
540 &dmaWriteEvent);
541
542 return;
543 }
544
545 // setup the initial page and DMA address
546 curAddr = curPrd.getBaseAddr();
547 pageAddr = TheISA::TruncPage(curAddr);
548 dmaAddr = pciToDma(curAddr);
549
550 // clear out the data buffer
551 memset(dataBuffer, 0, MAX_DMA_SIZE);
552
553 while (bytesRead < curPrd.getByteCount()) {
554 // see if we have crossed into a new page
555 if (pageAddr != TheISA::TruncPage(curAddr)) {
556 // write the data to memory
557 memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
558 (void *)(dataBuffer + (bytesRead - bytesInPage)),
559 bytesInPage);
560
561 // update the DMA address and page address
562 pageAddr = TheISA::TruncPage(curAddr);
563 dmaAddr = pciToDma(curAddr);
564
565 bytesInPage = 0;
566 }
567
568 if (cmdBytesLeft <= 0)
569 panic("DMA requested data is larger than # sectors specified\n");
570
571 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
572
573 curAddr += SectorSize;
574 bytesRead += SectorSize;
575 bytesInPage += SectorSize;
576 cmdBytesLeft -= SectorSize;
577 }
578
579 // write the last page worth read to memory
580 if (bytesInPage != 0) {
581 memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
582 (void *)(dataBuffer + (bytesRead - bytesInPage)),
583 bytesInPage);
584 }
585
586 // check for the EOT
587 if (curPrd.getEOT()) {
588 assert(cmdBytesLeft == 0);
589 dmaState = Dma_Idle;
590 updateState(ACT_DMA_DONE);
591 } else {
592 doDmaTransfer();
593 }
594 }
595
596 ////
597 // Disk utility routines
598 ///
599
600 void
601 IdeDisk::readDisk(uint32_t sector, uint8_t *data)
602 {
603 uint32_t bytesRead = image->read(data, sector);
604
605 if (bytesRead != SectorSize)
606 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
607 name(), bytesRead, SectorSize, errno);
608 }
609
610 void
611 IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
612 {
613 uint32_t bytesWritten = image->write(data, sector);
614
615 if (bytesWritten != SectorSize)
616 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
617 name(), bytesWritten, SectorSize, errno);
618 }
619
620 ////
621 // Setup and handle commands
622 ////
623
624 void
625 IdeDisk::startDma(const uint32_t &prdTableBase)
626 {
627 if (dmaState != Dma_Start)
628 panic("Inconsistent DMA state, should be in Dma_Start!\n");
629
630 if (devState != Transfer_Data_Dma)
631 panic("Inconsistent device state for DMA start!\n");
632
633 // PRD base address is given by bits 31:2
634 curPrdAddr = pciToDma((Addr)(prdTableBase & ~ULL(0x3)));
635
636 dmaState = Dma_Transfer;
637
638 // schedule dma transfer (doDmaTransfer)
639 dmaTransferEvent.schedule(curTick + 1);
640 }
641
642 void
643 IdeDisk::abortDma()
644 {
645 if (dmaState == Dma_Idle)
646 panic("Inconsistent DMA state, should be Start or Transfer!");
647
648 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
649 panic("Inconsistent device state, should be Transfer or Prepare!\n");
650
651 updateState(ACT_CMD_ERROR);
652 }
653
654 void
655 IdeDisk::startCommand()
656 {
657 DevAction_t action = ACT_NONE;
658 uint32_t size = 0;
659 dmaRead = false;
660
661 // Decode commands
662 switch (cmdReg.command) {
663 // Supported non-data commands
664 case WDSF_READ_NATIVE_MAX:
665 size = image->size() - 1;
666 cmdReg.sec_num = (size & 0xff);
667 cmdReg.cyl_low = ((size & 0xff00) >> 8);
668 cmdReg.cyl_high = ((size & 0xff0000) >> 16);
669 cmdReg.head = ((size & 0xf000000) >> 24);
670
671 devState = Command_Execution;
672 action = ACT_CMD_COMPLETE;
673 break;
674
675 case WDCC_RECAL:
676 case WDCC_IDP:
677 case WDCC_STANDBY_IMMED:
678 case WDCC_FLUSHCACHE:
679 case WDSF_VERIFY:
680 case WDSF_SEEK:
681 case SET_FEATURES:
682 case WDCC_SETMULTI:
683 devState = Command_Execution;
684 action = ACT_CMD_COMPLETE;
685 break;
686
687 // Supported PIO data-in commands
688 case WDCC_IDENTIFY:
689 cmdBytes = cmdBytesLeft = sizeof(struct ataparams);
690 devState = Prepare_Data_In;
691 action = ACT_DATA_READY;
692 break;
693
694 case WDCC_READMULTI:
695 case WDCC_READ:
696 if (!(cmdReg.drive & DRIVE_LBA_BIT))
697 panic("Attempt to perform CHS access, only supports LBA\n");
698
699 if (cmdReg.sec_count == 0)
700 cmdBytes = cmdBytesLeft = (256 * SectorSize);
701 else
702 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
703
704 curSector = getLBABase();
705
706 /** @todo make this a scheduled event to simulate disk delay */
707 devState = Prepare_Data_In;
708 action = ACT_DATA_READY;
709 break;
710
711 // Supported PIO data-out commands
712 case WDCC_WRITEMULTI:
713 case WDCC_WRITE:
714 if (!(cmdReg.drive & DRIVE_LBA_BIT))
715 panic("Attempt to perform CHS access, only supports LBA\n");
716
717 if (cmdReg.sec_count == 0)
718 cmdBytes = cmdBytesLeft = (256 * SectorSize);
719 else
720 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
721
722 curSector = getLBABase();
723
724 devState = Prepare_Data_Out;
725 action = ACT_DATA_READY;
726 break;
727
728 // Supported DMA commands
729 case WDCC_WRITEDMA:
730 dmaRead = true; // a write to the disk is a DMA read from memory
731 case WDCC_READDMA:
732 if (!(cmdReg.drive & DRIVE_LBA_BIT))
733 panic("Attempt to perform CHS access, only supports LBA\n");
734
735 if (cmdReg.sec_count == 0)
736 cmdBytes = cmdBytesLeft = (256 * SectorSize);
737 else
738 cmdBytes = cmdBytesLeft = (cmdReg.sec_count * SectorSize);
739
740 curSector = getLBABase();
741
742 devState = Prepare_Data_Dma;
743 action = ACT_DMA_READY;
744 break;
745
746 default:
747 panic("Unsupported ATA command: %#x\n", cmdReg.command);
748 }
749
750 if (action != ACT_NONE) {
751 // set the BSY bit
752 status |= STATUS_BSY_BIT;
753 // clear the DRQ bit
754 status &= ~STATUS_DRQ_BIT;
755 // clear the DF bit
756 status &= ~STATUS_DF_BIT;
757
758 updateState(action);
759 }
760 }
761
762 ////
763 // Handle setting and clearing interrupts
764 ////
765
766 void
767 IdeDisk::intrPost()
768 {
769 DPRINTF(IdeDisk, "Posting Interrupt\n");
770 if (intrPending)
771 panic("Attempt to post an interrupt with one pending\n");
772
773 intrPending = true;
774
775 // talk to controller to set interrupt
776 if (ctrl) {
777 ctrl->bmi_regs.bmis0 |= IDEINTS;
778 ctrl->intrPost();
779 }
780 }
781
782 void
783 IdeDisk::intrClear()
784 {
785 DPRINTF(IdeDisk, "Clearing Interrupt\n");
786 if (!intrPending)
787 panic("Attempt to clear a non-pending interrupt\n");
788
789 intrPending = false;
790
791 // talk to controller to clear interrupt
792 if (ctrl)
793 ctrl->intrClear();
794 }
795
796 ////
797 // Manage the device internal state machine
798 ////
799
800 void
801 IdeDisk::updateState(DevAction_t action)
802 {
803 switch (devState) {
804 case Device_Srst:
805 if (action == ACT_SRST_SET) {
806 // set the BSY bit
807 status |= STATUS_BSY_BIT;
808 } else if (action == ACT_SRST_CLEAR) {
809 // clear the BSY bit
810 status &= ~STATUS_BSY_BIT;
811
812 // reset the device state
813 reset(devID);
814 }
815 break;
816
817 case Device_Idle_S:
818 if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
819 devState = Device_Idle_NS;
820 } else if (action == ACT_CMD_WRITE) {
821 startCommand();
822 }
823
824 break;
825
826 case Device_Idle_SI:
827 if (action == ACT_SELECT_WRITE && !isDEVSelect()) {
828 devState = Device_Idle_NS;
829 intrClear();
830 } else if (action == ACT_STAT_READ || isIENSet()) {
831 devState = Device_Idle_S;
832 intrClear();
833 } else if (action == ACT_CMD_WRITE) {
834 intrClear();
835 startCommand();
836 }
837
838 break;
839
840 case Device_Idle_NS:
841 if (action == ACT_SELECT_WRITE && isDEVSelect()) {
842 if (!isIENSet() && intrPending) {
843 devState = Device_Idle_SI;
844 intrPost();
845 }
846 if (isIENSet() || !intrPending) {
847 devState = Device_Idle_S;
848 }
849 }
850 break;
851
852 case Command_Execution:
853 if (action == ACT_CMD_COMPLETE) {
854 // clear the BSY bit
855 setComplete();
856
857 if (!isIENSet()) {
858 devState = Device_Idle_SI;
859 intrPost();
860 } else {
861 devState = Device_Idle_S;
862 }
863 }
864 break;
865
866 case Prepare_Data_In:
867 if (action == ACT_CMD_ERROR) {
868 // clear the BSY bit
869 setComplete();
870
871 if (!isIENSet()) {
872 devState = Device_Idle_SI;
873 intrPost();
874 } else {
875 devState = Device_Idle_S;
876 }
877 } else if (action == ACT_DATA_READY) {
878 // clear the BSY bit
879 status &= ~STATUS_BSY_BIT;
880 // set the DRQ bit
881 status |= STATUS_DRQ_BIT;
882
883 // copy the data into the data buffer
884 if (cmdReg.command == WDCC_IDENTIFY) {
885 // Reset the drqBytes for this block
886 drqBytesLeft = sizeof(struct ataparams);
887
888 memcpy((void *)dataBuffer, (void *)&driveID,
889 sizeof(struct ataparams));
890 } else {
891 // Reset the drqBytes for this block
892 drqBytesLeft = SectorSize;
893
894 readDisk(curSector++, dataBuffer);
895 }
896
897 // put the first two bytes into the data register
898 memcpy((void *)&cmdReg.data, (void *)dataBuffer,
899 sizeof(uint16_t));
900
901 if (!isIENSet()) {
902 devState = Data_Ready_INTRQ_In;
903 intrPost();
904 } else {
905 devState = Transfer_Data_In;
906 }
907 }
908 break;
909
910 case Data_Ready_INTRQ_In:
911 if (action == ACT_STAT_READ) {
912 devState = Transfer_Data_In;
913 intrClear();
914 }
915 break;
916
917 case Transfer_Data_In:
918 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
919 if (action == ACT_DATA_READ_BYTE) {
920 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
921 } else {
922 drqBytesLeft -= 2;
923 cmdBytesLeft -= 2;
924
925 // copy next short into data registers
926 if (drqBytesLeft)
927 memcpy((void *)&cmdReg.data,
928 (void *)&dataBuffer[SectorSize - drqBytesLeft],
929 sizeof(uint16_t));
930 }
931
932 if (drqBytesLeft == 0) {
933 if (cmdBytesLeft == 0) {
934 // Clear the BSY bit
935 setComplete();
936 devState = Device_Idle_S;
937 } else {
938 devState = Prepare_Data_In;
939 // set the BSY_BIT
940 status |= STATUS_BSY_BIT;
941 // clear the DRQ_BIT
942 status &= ~STATUS_DRQ_BIT;
943
944 /** @todo change this to a scheduled event to simulate
945 disk delay */
946 updateState(ACT_DATA_READY);
947 }
948 }
949 }
950 break;
951
952 case Prepare_Data_Out:
953 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
954 // clear the BSY bit
955 setComplete();
956
957 if (!isIENSet()) {
958 devState = Device_Idle_SI;
959 intrPost();
960 } else {
961 devState = Device_Idle_S;
962 }
963 } else if (action == ACT_DATA_READY && cmdBytesLeft != 0) {
964 // clear the BSY bit
965 status &= ~STATUS_BSY_BIT;
966 // set the DRQ bit
967 status |= STATUS_DRQ_BIT;
968
969 // clear the data buffer to get it ready for writes
970 memset(dataBuffer, 0, MAX_DMA_SIZE);
971
972 // reset the drqBytes for this block
973 drqBytesLeft = SectorSize;
974
975 if (cmdBytesLeft == cmdBytes || isIENSet()) {
976 devState = Transfer_Data_Out;
977 } else {
978 devState = Data_Ready_INTRQ_Out;
979 intrPost();
980 }
981 }
982 break;
983
984 case Data_Ready_INTRQ_Out:
985 if (action == ACT_STAT_READ) {
986 devState = Transfer_Data_Out;
987 intrClear();
988 }
989 break;
990
991 case Transfer_Data_Out:
992 if (action == ACT_DATA_WRITE_BYTE ||
993 action == ACT_DATA_WRITE_SHORT) {
994
995 if (action == ACT_DATA_READ_BYTE) {
996 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
997 } else {
998 // copy the latest short into the data buffer
999 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
1000 (void *)&cmdReg.data,
1001 sizeof(uint16_t));
1002
1003 drqBytesLeft -= 2;
1004 cmdBytesLeft -= 2;
1005 }
1006
1007 if (drqBytesLeft == 0) {
1008 // copy the block to the disk
1009 writeDisk(curSector++, dataBuffer);
1010
1011 // set the BSY bit
1012 status |= STATUS_BSY_BIT;
1013 // set the seek bit
1014 status |= STATUS_SEEK_BIT;
1015 // clear the DRQ bit
1016 status &= ~STATUS_DRQ_BIT;
1017
1018 devState = Prepare_Data_Out;
1019
1020 /** @todo change this to a scheduled event to simulate
1021 disk delay */
1022 updateState(ACT_DATA_READY);
1023 }
1024 }
1025 break;
1026
1027 case Prepare_Data_Dma:
1028 if (action == ACT_CMD_ERROR) {
1029 // clear the BSY bit
1030 setComplete();
1031
1032 if (!isIENSet()) {
1033 devState = Device_Idle_SI;
1034 intrPost();
1035 } else {
1036 devState = Device_Idle_S;
1037 }
1038 } else if (action == ACT_DMA_READY) {
1039 // clear the BSY bit
1040 status &= ~STATUS_BSY_BIT;
1041 // set the DRQ bit
1042 status |= STATUS_DRQ_BIT;
1043
1044 devState = Transfer_Data_Dma;
1045
1046 if (dmaState != Dma_Idle)
1047 panic("Inconsistent DMA state, should be Dma_Idle\n");
1048
1049 dmaState = Dma_Start;
1050 // wait for the write to the DMA start bit
1051 }
1052 break;
1053
1054 case Transfer_Data_Dma:
1055 if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) {
1056 // clear the BSY bit
1057 setComplete();
1058 // set the seek bit
1059 status |= STATUS_SEEK_BIT;
1060 // clear the controller state for DMA transfer
1061 ctrl->setDmaComplete(this);
1062
1063 if (!isIENSet()) {
1064 devState = Device_Idle_SI;
1065 intrPost();
1066 } else {
1067 devState = Device_Idle_S;
1068 }
1069 }
1070 break;
1071
1072 default:
1073 panic("Unknown IDE device state: %#x\n", devState);
1074 }
1075 }
1076
1077 void
1078 IdeDisk::serialize(ostream &os)
1079 {
1080 // Check all outstanding events to see if they are scheduled
1081 // these are all mutually exclusive
1082 Tick reschedule = 0;
1083 Events_t event = None;
1084
1085 int eventCount = 0;
1086
1087 if (dmaTransferEvent.scheduled()) {
1088 reschedule = dmaTransferEvent.when();
1089 event = Transfer;
1090 eventCount++;
1091 }
1092 if (dmaReadWaitEvent.scheduled()) {
1093 reschedule = dmaReadWaitEvent.when();
1094 event = ReadWait;
1095 eventCount++;
1096 }
1097 if (dmaWriteWaitEvent.scheduled()) {
1098 reschedule = dmaWriteWaitEvent.when();
1099 event = WriteWait;
1100 eventCount++;
1101 }
1102 if (dmaPrdReadEvent.scheduled()) {
1103 reschedule = dmaPrdReadEvent.when();
1104 event = PrdRead;
1105 eventCount++;
1106 }
1107 if (dmaReadEvent.scheduled()) {
1108 reschedule = dmaReadEvent.when();
1109 event = DmaRead;
1110 eventCount++;
1111 }
1112 if (dmaWriteEvent.scheduled()) {
1113 reschedule = dmaWriteEvent.when();
1114 event = DmaWrite;
1115 eventCount++;
1116 }
1117
1118 assert(eventCount <= 1);
1119
1120 SERIALIZE_SCALAR(reschedule);
1121 SERIALIZE_ENUM(event);
1122
1123 // Serialize device registers
1124 SERIALIZE_SCALAR(cmdReg.data);
1125 SERIALIZE_SCALAR(cmdReg.sec_count);
1126 SERIALIZE_SCALAR(cmdReg.sec_num);
1127 SERIALIZE_SCALAR(cmdReg.cyl_low);
1128 SERIALIZE_SCALAR(cmdReg.cyl_high);
1129 SERIALIZE_SCALAR(cmdReg.drive);
1130 SERIALIZE_SCALAR(cmdReg.command);
1131 SERIALIZE_SCALAR(status);
1132 SERIALIZE_SCALAR(nIENBit);
1133 SERIALIZE_SCALAR(devID);
1134
1135 // Serialize the PRD related information
1136 SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1137 SERIALIZE_SCALAR(curPrd.entry.byteCount);
1138 SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1139 SERIALIZE_SCALAR(curPrdAddr);
1140
1141 // Serialize current transfer related information
1142 SERIALIZE_SCALAR(cmdBytesLeft);
1143 SERIALIZE_SCALAR(cmdBytes);
1144 SERIALIZE_SCALAR(drqBytesLeft);
1145 SERIALIZE_SCALAR(curSector);
1146 SERIALIZE_SCALAR(dmaRead);
1147 SERIALIZE_SCALAR(dmaInterfaceBytes);
1148 SERIALIZE_SCALAR(intrPending);
1149 SERIALIZE_ENUM(devState);
1150 SERIALIZE_ENUM(dmaState);
1151 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1152 }
1153
1154 void
1155 IdeDisk::unserialize(Checkpoint *cp, const string &section)
1156 {
1157 // Reschedule events that were outstanding
1158 // these are all mutually exclusive
1159 Tick reschedule = 0;
1160 Events_t event = None;
1161
1162 UNSERIALIZE_SCALAR(reschedule);
1163 UNSERIALIZE_ENUM(event);
1164
1165 switch (event) {
1166 case None : break;
1167 case Transfer : dmaTransferEvent.schedule(reschedule); break;
1168 case ReadWait : dmaReadWaitEvent.schedule(reschedule); break;
1169 case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break;
1170 case PrdRead : dmaPrdReadEvent.schedule(reschedule); break;
1171 case DmaRead : dmaReadEvent.schedule(reschedule); break;
1172 case DmaWrite : dmaWriteEvent.schedule(reschedule); break;
1173 }
1174
1175 // Unserialize device registers
1176 UNSERIALIZE_SCALAR(cmdReg.data);
1177 UNSERIALIZE_SCALAR(cmdReg.sec_count);
1178 UNSERIALIZE_SCALAR(cmdReg.sec_num);
1179 UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1180 UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1181 UNSERIALIZE_SCALAR(cmdReg.drive);
1182 UNSERIALIZE_SCALAR(cmdReg.command);
1183 UNSERIALIZE_SCALAR(status);
1184 UNSERIALIZE_SCALAR(nIENBit);
1185 UNSERIALIZE_SCALAR(devID);
1186
1187 // Unserialize the PRD related information
1188 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1189 UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1190 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1191 UNSERIALIZE_SCALAR(curPrdAddr);
1192
1193 // Unserialize current transfer related information
1194 UNSERIALIZE_SCALAR(cmdBytes);
1195 UNSERIALIZE_SCALAR(cmdBytesLeft);
1196 UNSERIALIZE_SCALAR(drqBytesLeft);
1197 UNSERIALIZE_SCALAR(curSector);
1198 UNSERIALIZE_SCALAR(dmaRead);
1199 UNSERIALIZE_SCALAR(dmaInterfaceBytes);
1200 UNSERIALIZE_SCALAR(intrPending);
1201 UNSERIALIZE_ENUM(devState);
1202 UNSERIALIZE_ENUM(dmaState);
1203 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1204 }
1205
1206 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1207
1208 enum DriveID { master, slave };
1209 static const char *DriveID_strings[] = { "master", "slave" };
1210 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
1211
1212 SimObjectParam<DiskImage *> image;
1213 SimObjectParam<PhysicalMemory *> physmem;
1214 SimpleEnumParam<DriveID> driveID;
1215 Param<int> delay;
1216
1217 END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
1218
1219 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
1220
1221 INIT_PARAM(image, "Disk image"),
1222 INIT_PARAM(physmem, "Physical memory"),
1223 INIT_ENUM_PARAM(driveID, "Drive ID (0=master 1=slave)", DriveID_strings),
1224 INIT_PARAM_DFLT(delay, "Fixed disk delay in microseconds", 1)
1225
1226 END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
1227
1228
1229 CREATE_SIM_OBJECT(IdeDisk)
1230 {
1231 return new IdeDisk(getInstanceName(), image, physmem, driveID, delay);
1232 }
1233
1234 REGISTER_SIM_OBJECT("IdeDisk", IdeDisk)
1235
1236 #endif //DOXYGEN_SHOULD_SKIP_THIS