merge m5 with linux for the event and binning lifting
[gem5.git] / dev / ide_disk.cc
1 /*
2 * Copyright (c) 2003 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 "arch/alpha/pmap.h"
39 #include "base/cprintf.hh" // csprintf
40 #include "base/trace.hh"
41 #include "dev/disk_image.hh"
42 #include "dev/ide_disk.hh"
43 #include "dev/ide_ctrl.hh"
44 #include "dev/tsunami.hh"
45 #include "dev/tsunami_pchip.hh"
46 #include "mem/functional_mem/physical_memory.hh"
47 #include "mem/bus/bus.hh"
48 #include "mem/bus/dma_interface.hh"
49 #include "mem/bus/pio_interface.hh"
50 #include "mem/bus/pio_interface_impl.hh"
51 #include "sim/builder.hh"
52 #include "sim/sim_object.hh"
53 #include "sim/universe.hh"
54
55 using namespace std;
56
57 IdeDisk::IdeDisk(const string &name, DiskImage *img, PhysicalMemory *phys,
58 int id, int delay)
59 : SimObject(name), ctrl(NULL), image(img), physmem(phys),
60 dmaTransferEvent(this), dmaReadWaitEvent(this),
61 dmaWriteWaitEvent(this), dmaPrdReadEvent(this),
62 dmaReadEvent(this), dmaWriteEvent(this)
63 {
64 // calculate disk delay in microseconds
65 diskDelay = (delay * ticksPerSecond / 100000);
66
67 // initialize the data buffer and shadow registers
68 dataBuffer = new uint8_t[MAX_DMA_SIZE];
69
70 memset(dataBuffer, 0, MAX_DMA_SIZE);
71 memset(&cmdReg, 0, sizeof(CommandReg_t));
72 memset(&curPrd.entry, 0, sizeof(PrdEntry_t));
73
74 dmaInterfaceBytes = 0;
75 curPrdAddr = 0;
76 curSector = 0;
77 curCommand = 0;
78 cmdBytesLeft = 0;
79 drqBytesLeft = 0;
80 dmaRead = false;
81 intrPending = false;
82
83 // fill out the drive ID structure
84 memset(&driveID, 0, sizeof(struct hd_driveid));
85
86 // Calculate LBA and C/H/S values
87 uint16_t cylinders;
88 uint8_t heads;
89 uint8_t sectors;
90
91 uint32_t lba_size = image->size();
92 if (lba_size >= 16383*16*63) {
93 cylinders = 16383;
94 heads = 16;
95 sectors = 63;
96 } else {
97 if (lba_size >= 63)
98 sectors = 63;
99 else
100 sectors = lba_size;
101
102 if ((lba_size / sectors) >= 16)
103 heads = 16;
104 else
105 heads = (lba_size / sectors);
106
107 cylinders = lba_size / (heads * sectors);
108 }
109
110 // Setup the model name
111 sprintf((char *)driveID.model, "5MI EDD si k");
112 // Set the maximum multisector transfer size
113 driveID.max_multsect = MAX_MULTSECT;
114 // IORDY supported, IORDY disabled, LBA enabled, DMA enabled
115 driveID.capability = 0x7;
116 // UDMA support, EIDE support
117 driveID.field_valid = 0x6;
118 // Setup default C/H/S settings
119 driveID.cyls = cylinders;
120 driveID.sectors = sectors;
121 driveID.heads = heads;
122 // Setup the current multisector transfer size
123 driveID.multsect = MAX_MULTSECT;
124 driveID.multsect_valid = 0x1;
125 // Number of sectors on disk
126 driveID.lba_capacity = lba_size;
127 // Multiword DMA mode 2 and below supported
128 driveID.dma_mword = 0x400;
129 // Set PIO mode 4 and 3 supported
130 driveID.eide_pio_modes = 0x3;
131 // Set DMA mode 4 and below supported
132 driveID.dma_ultra = 0x10;
133 // Statically set hardware config word
134 driveID.hw_config = 0x4001;
135
136 // set the device state to idle
137 dmaState = Dma_Idle;
138
139 if (id == DEV0) {
140 devState = Device_Idle_S;
141 devID = DEV0;
142 } else if (id == DEV1) {
143 devState = Device_Idle_NS;
144 devID = DEV1;
145 } else {
146 panic("Invalid device ID: %#x\n", id);
147 }
148
149 // set the device ready bit
150 cmdReg.status |= STATUS_DRDY_BIT;
151 }
152
153 IdeDisk::~IdeDisk()
154 {
155 // destroy the data buffer
156 delete [] dataBuffer;
157 }
158
159 ////
160 // Utility functions
161 ////
162
163 Addr
164 IdeDisk::pciToDma(Addr pciAddr)
165 {
166 if (ctrl)
167 return ctrl->tsunami->pchip->translatePciToDma(pciAddr);
168 else
169 panic("Access to unset controller!\n");
170 }
171
172 uint32_t
173 IdeDisk::bytesInDmaPage(Addr curAddr, uint32_t bytesLeft)
174 {
175 uint32_t bytesInPage = 0;
176
177 // First calculate how many bytes could be in the page
178 if (bytesLeft > ALPHA_PGBYTES)
179 bytesInPage = ALPHA_PGBYTES;
180 else
181 bytesInPage = bytesLeft;
182
183 // Next, see if we have crossed a page boundary, and adjust
184 Addr upperBound = curAddr + bytesInPage;
185 Addr pageBound = alpha_trunc_page(curAddr) + ALPHA_PGBYTES;
186
187 assert(upperBound >= curAddr && "DMA read wraps around address space!\n");
188
189 if (upperBound >= pageBound)
190 bytesInPage = pageBound - curAddr;
191
192 return bytesInPage;
193 }
194
195 ////
196 // Device registers read/write
197 ////
198
199 void
200 IdeDisk::read(const Addr &offset, bool byte, bool cmdBlk, uint8_t *data)
201 {
202 DevAction_t action = ACT_NONE;
203
204 if (cmdBlk) {
205 if (offset < 0 || offset > sizeof(CommandReg_t))
206 panic("Invalid disk command register offset: %#x\n", offset);
207
208 if (!byte && offset != DATA_OFFSET)
209 panic("Invalid 16-bit read, only allowed on data reg\n");
210
211 if (!byte)
212 *(uint16_t *)data = *(uint16_t *)&cmdReg.data0;
213 else
214 *data = ((uint8_t *)&cmdReg)[offset];
215
216 // determine if an action needs to be taken on the state machine
217 if (offset == STATUS_OFFSET) {
218 action = ACT_STAT_READ;
219 } else if (offset == DATA_OFFSET) {
220 if (byte)
221 action = ACT_DATA_READ_BYTE;
222 else
223 action = ACT_DATA_READ_SHORT;
224 }
225
226 } else {
227 if (offset != ALTSTAT_OFFSET)
228 panic("Invalid disk control register offset: %#x\n", offset);
229
230 if (!byte)
231 panic("Invalid 16-bit read from control block\n");
232
233 *data = ((uint8_t *)&cmdReg)[STATUS_OFFSET];
234 }
235
236 if (action != ACT_NONE)
237 updateState(action);
238 }
239
240 void
241 IdeDisk::write(const Addr &offset, bool byte, bool cmdBlk, const uint8_t *data)
242 {
243 DevAction_t action = ACT_NONE;
244
245 if (cmdBlk) {
246 if (offset < 0 || offset > sizeof(CommandReg_t))
247 panic("Invalid disk command register offset: %#x\n", offset);
248
249 if (!byte && offset != DATA_OFFSET)
250 panic("Invalid 16-bit write, only allowed on data reg\n");
251
252 if (!byte)
253 *((uint16_t *)&cmdReg.data0) = *(uint16_t *)data;
254 else
255 ((uint8_t *)&cmdReg)[offset] = *data;
256
257 // determine if an action needs to be taken on the state machine
258 if (offset == COMMAND_OFFSET) {
259 action = ACT_CMD_WRITE;
260 } else if (offset == DATA_OFFSET) {
261 if (byte)
262 action = ACT_DATA_WRITE_BYTE;
263 else
264 action = ACT_DATA_WRITE_SHORT;
265 }
266
267 } else {
268 if (offset != CONTROL_OFFSET)
269 panic("Invalid disk control register offset: %#x\n", offset);
270
271 if (!byte)
272 panic("Invalid 16-bit write to control block\n");
273
274 if (*data & CONTROL_RST_BIT)
275 panic("Software reset not supported!\n");
276
277 nIENBit = (*data & CONTROL_IEN_BIT) ? true : false;
278 }
279
280 if (action != ACT_NONE)
281 updateState(action);
282 }
283
284 ////
285 // Perform DMA transactions
286 ////
287
288 void
289 IdeDisk::doDmaTransfer()
290 {
291 if (dmaState != Dma_Transfer || devState != Transfer_Data_Dma)
292 panic("Inconsistent DMA transfer state: dmaState = %d devState = %d\n",
293 dmaState, devState);
294
295 // first read the current PRD
296 if (dmaInterface) {
297 if (dmaInterface->busy()) {
298 // reschedule after waiting period
299 dmaTransferEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
300 return;
301 }
302
303 dmaInterface->doDMA(Read, curPrdAddr, sizeof(PrdEntry_t), curTick,
304 &dmaPrdReadEvent);
305 } else {
306 dmaPrdReadDone();
307 }
308 }
309
310 void
311 IdeDisk::dmaPrdReadDone()
312 {
313 // actually copy the PRD from physical memory
314 memcpy((void *)&curPrd.entry,
315 physmem->dma_addr(curPrdAddr, sizeof(PrdEntry_t)),
316 sizeof(PrdEntry_t));
317
318 curPrdAddr += sizeof(PrdEntry_t);
319
320 if (dmaRead)
321 doDmaRead();
322 else
323 doDmaWrite();
324 }
325
326 void
327 IdeDisk::doDmaRead()
328 {
329 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
330
331 if (dmaInterface) {
332 if (dmaInterface->busy()) {
333 // reschedule after waiting period
334 dmaReadWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
335 return;
336 }
337
338 Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
339
340 uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
341 (uint32_t)curPrd.getByteCount());
342
343 dmaInterfaceBytes = bytesInPage;
344
345 dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
346 curTick + totalDiskDelay, &dmaReadEvent);
347 } else {
348 // schedule dmaReadEvent with sectorDelay (dmaReadDone)
349 dmaReadEvent.schedule(curTick + totalDiskDelay);
350 }
351 }
352
353 void
354 IdeDisk::dmaReadDone()
355 {
356
357 Addr curAddr = 0, dmaAddr = 0;
358 uint32_t bytesWritten = 0, bytesInPage = 0, bytesLeft = 0;
359
360 // continue to use the DMA interface until all pages are read
361 if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
362 // see if the interface is busy
363 if (dmaInterface->busy()) {
364 // reschedule after waiting period
365 dmaReadEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
366 return;
367 }
368
369 uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
370 curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
371 dmaAddr = pciToDma(curAddr);
372
373 bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
374 dmaInterfaceBytes += bytesInPage;
375
376 dmaInterface->doDMA(Read, dmaAddr, bytesInPage,
377 curTick, &dmaReadEvent);
378
379 return;
380 }
381
382 // set initial address
383 curAddr = curPrd.getBaseAddr();
384
385 // clear out the data buffer
386 memset(dataBuffer, 0, MAX_DMA_SIZE);
387
388 // read the data from memory via DMA into a data buffer
389 while (bytesWritten < curPrd.getByteCount()) {
390 if (cmdBytesLeft <= 0)
391 panic("DMA data is larger than # of sectors specified\n");
392
393 dmaAddr = pciToDma(curAddr);
394
395 // calculate how many bytes are in the current page
396 bytesLeft = curPrd.getByteCount() - bytesWritten;
397 bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
398
399 // copy the data from memory into the data buffer
400 memcpy((void *)(dataBuffer + bytesWritten),
401 physmem->dma_addr(dmaAddr, bytesInPage),
402 bytesInPage);
403
404 curAddr += bytesInPage;
405 bytesWritten += bytesInPage;
406 cmdBytesLeft -= bytesInPage;
407 }
408
409 // write the data to the disk image
410 for (bytesWritten = 0;
411 bytesWritten < curPrd.getByteCount();
412 bytesWritten += SectorSize) {
413
414 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
415 }
416
417 #if 0
418 // actually copy the data from memory to data buffer
419 Addr dmaAddr =
420 ctrl->tsunami->pchip->translatePciToDma(curPrd.getBaseAddr());
421 memcpy((void *)dataBuffer,
422 physmem->dma_addr(dmaAddr, curPrd.getByteCount()),
423 curPrd.getByteCount());
424
425 uint32_t bytesWritten = 0;
426
427 while (bytesWritten < curPrd.getByteCount()) {
428 if (cmdBytesLeft <= 0)
429 panic("DMA data is larger than # sectors specified\n");
430
431 writeDisk(curSector++, (uint8_t *)(dataBuffer + bytesWritten));
432
433 bytesWritten += SectorSize;
434 cmdBytesLeft -= SectorSize;
435 }
436 #endif
437
438 // check for the EOT
439 if (curPrd.getEOT()){
440 assert(cmdBytesLeft == 0);
441 dmaState = Dma_Idle;
442 updateState(ACT_DMA_DONE);
443 } else {
444 doDmaTransfer();
445 }
446 }
447
448 void
449 IdeDisk::doDmaWrite()
450 {
451 Tick totalDiskDelay = diskDelay + (curPrd.getByteCount() / SectorSize);
452
453 if (dmaInterface) {
454 if (dmaInterface->busy()) {
455 // reschedule after waiting period
456 dmaWriteWaitEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
457 return;
458 }
459
460 Addr dmaAddr = pciToDma(curPrd.getBaseAddr());
461
462 uint32_t bytesInPage = bytesInDmaPage(curPrd.getBaseAddr(),
463 (uint32_t)curPrd.getByteCount());
464
465 dmaInterfaceBytes = bytesInPage;
466
467 dmaInterface->doDMA(WriteInvalidate, dmaAddr,
468 bytesInPage, curTick + totalDiskDelay,
469 &dmaWriteEvent);
470 } else {
471 // schedule event with disk delay (dmaWriteDone)
472 dmaWriteEvent.schedule(curTick + totalDiskDelay);
473 }
474 }
475
476 void
477 IdeDisk::dmaWriteDone()
478 {
479 Addr curAddr = 0, pageAddr = 0, dmaAddr = 0;
480 uint32_t bytesRead = 0, bytesInPage = 0;
481
482 // continue to use the DMA interface until all pages are read
483 if (dmaInterface && (dmaInterfaceBytes < curPrd.getByteCount())) {
484 // see if the interface is busy
485 if (dmaInterface->busy()) {
486 // reschedule after waiting period
487 dmaWriteEvent.schedule(curTick + DMA_BACKOFF_PERIOD);
488 return;
489 }
490
491 uint32_t bytesLeft = curPrd.getByteCount() - dmaInterfaceBytes;
492 curAddr = curPrd.getBaseAddr() + dmaInterfaceBytes;
493 dmaAddr = pciToDma(curAddr);
494
495 bytesInPage = bytesInDmaPage(curAddr, bytesLeft);
496 dmaInterfaceBytes += bytesInPage;
497
498 dmaInterface->doDMA(WriteInvalidate, dmaAddr,
499 bytesInPage, curTick,
500 &dmaWriteEvent);
501
502 return;
503 }
504
505 // setup the initial page and DMA address
506 curAddr = curPrd.getBaseAddr();
507 pageAddr = alpha_trunc_page(curAddr);
508 dmaAddr = pciToDma(curAddr);
509
510 // clear out the data buffer
511 memset(dataBuffer, 0, MAX_DMA_SIZE);
512
513 while (bytesRead < curPrd.getByteCount()) {
514 // see if we have crossed into a new page
515 if (pageAddr != alpha_trunc_page(curAddr)) {
516 // write the data to memory
517 memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
518 (void *)(dataBuffer + (bytesRead - bytesInPage)),
519 bytesInPage);
520
521 // update the DMA address and page address
522 pageAddr = alpha_trunc_page(curAddr);
523 dmaAddr = pciToDma(curAddr);
524
525 bytesInPage = 0;
526 }
527
528 if (cmdBytesLeft <= 0)
529 panic("DMA requested data is larger than # sectors specified\n");
530
531 readDisk(curSector++, (uint8_t *)(dataBuffer + bytesRead));
532
533 curAddr += SectorSize;
534 bytesRead += SectorSize;
535 bytesInPage += SectorSize;
536 cmdBytesLeft -= SectorSize;
537 }
538
539 // write the last page worth read to memory
540 if (bytesInPage != 0) {
541 memcpy(physmem->dma_addr(dmaAddr, bytesInPage),
542 (void *)(dataBuffer + (bytesRead - bytesInPage)),
543 bytesInPage);
544 }
545
546 #if 0
547 Addr dmaAddr = ctrl->tsunami->pchip->
548 translatePciToDma(curPrd.getBaseAddr());
549
550 memcpy(physmem->dma_addr(dmaAddr, curPrd.getByteCount()),
551 (void *)dataBuffer, curPrd.getByteCount());
552 #endif
553
554 // check for the EOT
555 if (curPrd.getEOT()) {
556 assert(cmdBytesLeft == 0);
557 dmaState = Dma_Idle;
558 updateState(ACT_DMA_DONE);
559 } else {
560 doDmaTransfer();
561 }
562 }
563
564 ////
565 // Disk utility routines
566 ///
567
568 void
569 IdeDisk::readDisk(uint32_t sector, uint8_t *data)
570 {
571 uint32_t bytesRead = image->read(data, sector);
572
573 if (bytesRead != SectorSize)
574 panic("Can't read from %s. Only %d of %d read. errno=%d\n",
575 name(), bytesRead, SectorSize, errno);
576 }
577
578 void
579 IdeDisk::writeDisk(uint32_t sector, uint8_t *data)
580 {
581 uint32_t bytesWritten = image->write(data, sector);
582
583 if (bytesWritten != SectorSize)
584 panic("Can't write to %s. Only %d of %d written. errno=%d\n",
585 name(), bytesWritten, SectorSize, errno);
586 }
587
588 ////
589 // Setup and handle commands
590 ////
591
592 void
593 IdeDisk::startDma(const uint32_t &prdTableBase)
594 {
595 if (dmaState != Dma_Start)
596 panic("Inconsistent DMA state, should be in Dma_Start!\n");
597
598 if (devState != Transfer_Data_Dma)
599 panic("Inconsistent device state for DMA start!\n");
600
601 curPrdAddr = pciToDma((Addr)prdTableBase);
602
603 dmaState = Dma_Transfer;
604
605 // schedule dma transfer (doDmaTransfer)
606 dmaTransferEvent.schedule(curTick + 1);
607 }
608
609 void
610 IdeDisk::abortDma()
611 {
612 if (dmaState == Dma_Idle)
613 panic("Inconsistent DMA state, should be in Dma_Start or Dma_Transfer!\n");
614
615 if (devState != Transfer_Data_Dma && devState != Prepare_Data_Dma)
616 panic("Inconsistent device state, should be in Transfer or Prepare!\n");
617
618 updateState(ACT_CMD_ERROR);
619 }
620
621 void
622 IdeDisk::startCommand()
623 {
624 DevAction_t action = ACT_NONE;
625 uint32_t size = 0;
626 dmaRead = false;
627
628 // copy the command to the shadow
629 curCommand = cmdReg.command;
630
631 // Decode commands
632 switch (cmdReg.command) {
633 // Supported non-data commands
634 case WIN_READ_NATIVE_MAX:
635 size = image->size() - 1;
636 cmdReg.sec_num = (size & 0xff);
637 cmdReg.cyl_low = ((size & 0xff00) >> 8);
638 cmdReg.cyl_high = ((size & 0xff0000) >> 16);
639 cmdReg.head = ((size & 0xf000000) >> 24);
640
641 devState = Command_Execution;
642 action = ACT_CMD_COMPLETE;
643 break;
644
645 case WIN_RECAL:
646 case WIN_SPECIFY:
647 case WIN_FLUSH_CACHE:
648 case WIN_VERIFY:
649 case WIN_SEEK:
650 case WIN_SETFEATURES:
651 case WIN_SETMULT:
652 devState = Command_Execution;
653 action = ACT_CMD_COMPLETE;
654 break;
655
656 // Supported PIO data-in commands
657 case WIN_IDENTIFY:
658 cmdBytesLeft = drqBytesLeft = sizeof(struct hd_driveid);
659 devState = Prepare_Data_In;
660 action = ACT_DATA_READY;
661 break;
662
663 case WIN_MULTREAD:
664 case WIN_READ:
665 if (!(cmdReg.drive & DRIVE_LBA_BIT))
666 panic("Attempt to perform CHS access, only supports LBA\n");
667
668 if (cmdReg.sec_count == 0)
669 cmdBytesLeft = (256 * SectorSize);
670 else
671 cmdBytesLeft = (cmdReg.sec_count * SectorSize);
672
673 drqBytesLeft = SectorSize;
674 curSector = getLBABase();
675
676 devState = Prepare_Data_In;
677 action = ACT_DATA_READY;
678 break;
679
680 // Supported PIO data-out commands
681 case WIN_MULTWRITE:
682 case WIN_WRITE:
683 if (!(cmdReg.drive & DRIVE_LBA_BIT))
684 panic("Attempt to perform CHS access, only supports LBA\n");
685
686 if (cmdReg.sec_count == 0)
687 cmdBytesLeft = (256 * SectorSize);
688 else
689 cmdBytesLeft = (cmdReg.sec_count * SectorSize);
690
691 drqBytesLeft = SectorSize;
692 curSector = getLBABase();
693
694 devState = Prepare_Data_Out;
695 action = ACT_DATA_READY;
696 break;
697
698 // Supported DMA commands
699 case WIN_WRITEDMA:
700 dmaRead = true; // a write to the disk is a DMA read from memory
701 case WIN_READDMA:
702 if (!(cmdReg.drive & DRIVE_LBA_BIT))
703 panic("Attempt to perform CHS access, only supports LBA\n");
704
705 if (cmdReg.sec_count == 0)
706 cmdBytesLeft = (256 * SectorSize);
707 else
708 cmdBytesLeft = (cmdReg.sec_count * SectorSize);
709
710 drqBytesLeft = SectorSize;
711 curSector = getLBABase();
712
713 devState = Prepare_Data_Dma;
714 action = ACT_DMA_READY;
715 break;
716
717 default:
718 panic("Unsupported ATA command: %#x\n", cmdReg.command);
719 }
720
721 if (action != ACT_NONE) {
722 // set the BSY bit
723 cmdReg.status |= STATUS_BSY_BIT;
724 // clear the DRQ bit
725 cmdReg.status &= ~STATUS_DRQ_BIT;
726
727 updateState(action);
728 }
729 }
730
731 ////
732 // Handle setting and clearing interrupts
733 ////
734
735 void
736 IdeDisk::intrPost()
737 {
738 if (intrPending)
739 panic("Attempt to post an interrupt with one pending\n");
740
741 intrPending = true;
742
743 // talk to controller to set interrupt
744 if (ctrl)
745 ctrl->intrPost();
746 }
747
748 void
749 IdeDisk::intrClear()
750 {
751 if (!intrPending)
752 panic("Attempt to clear a non-pending interrupt\n");
753
754 intrPending = false;
755
756 // talk to controller to clear interrupt
757 if (ctrl)
758 ctrl->intrClear();
759 }
760
761 ////
762 // Manage the device internal state machine
763 ////
764
765 void
766 IdeDisk::updateState(DevAction_t action)
767 {
768 switch (devState) {
769 case Device_Idle_S:
770 if (!isDEVSelect())
771 devState = Device_Idle_NS;
772 else if (action == ACT_CMD_WRITE)
773 startCommand();
774
775 break;
776
777 case Device_Idle_SI:
778 if (!isDEVSelect()) {
779 devState = Device_Idle_NS;
780 intrClear();
781 } else if (action == ACT_STAT_READ || isIENSet()) {
782 devState = Device_Idle_S;
783 intrClear();
784 } else if (action == ACT_CMD_WRITE) {
785 intrClear();
786 startCommand();
787 }
788
789 break;
790
791 case Device_Idle_NS:
792 if (isDEVSelect()) {
793 if (!isIENSet() && intrPending) {
794 devState = Device_Idle_SI;
795 intrPost();
796 }
797 if (isIENSet() || !intrPending) {
798 devState = Device_Idle_S;
799 }
800 }
801 break;
802
803 case Command_Execution:
804 if (action == ACT_CMD_COMPLETE) {
805 // clear the BSY bit
806 setComplete();
807
808 if (!isIENSet()) {
809 devState = Device_Idle_SI;
810 intrPost();
811 } else {
812 devState = Device_Idle_S;
813 }
814 }
815 break;
816
817 case Prepare_Data_In:
818 if (action == ACT_CMD_ERROR) {
819 // clear the BSY bit
820 setComplete();
821
822 if (!isIENSet()) {
823 devState = Device_Idle_SI;
824 intrPost();
825 } else {
826 devState = Device_Idle_S;
827 }
828 } else if (action == ACT_DATA_READY) {
829 // clear the BSY bit
830 cmdReg.status &= ~STATUS_BSY_BIT;
831 // set the DRQ bit
832 cmdReg.status |= STATUS_DRQ_BIT;
833
834 // put the first two bytes into the data register
835 memcpy((void *)&cmdReg.data0, (void *)dataBuffer,
836 sizeof(uint16_t));
837
838 // copy the data into the data buffer
839 if (curCommand == WIN_IDENTIFY)
840 memcpy((void *)dataBuffer, (void *)&driveID,
841 sizeof(struct hd_driveid));
842 else
843 readDisk(curSector++, dataBuffer);
844
845 if (!isIENSet()) {
846 devState = Data_Ready_INTRQ_In;
847 intrPost();
848 } else {
849 devState = Transfer_Data_In;
850 }
851 }
852 break;
853
854 case Data_Ready_INTRQ_In:
855 if (action == ACT_STAT_READ) {
856 devState = Transfer_Data_In;
857 intrClear();
858 }
859 break;
860
861 case Transfer_Data_In:
862 if (action == ACT_DATA_READ_BYTE || action == ACT_DATA_READ_SHORT) {
863 if (action == ACT_DATA_READ_BYTE) {
864 panic("DEBUG: READING DATA ONE BYTE AT A TIME!\n");
865 } else {
866 drqBytesLeft -= 2;
867 cmdBytesLeft -= 2;
868
869 // copy next short into data registers
870 memcpy((void *)&cmdReg.data0,
871 (void *)&dataBuffer[SectorSize - drqBytesLeft],
872 sizeof(uint16_t));
873 }
874
875 if (drqBytesLeft == 0) {
876 if (cmdBytesLeft == 0) {
877 // Clear the BSY bit
878 setComplete();
879 devState = Device_Idle_S;
880 } else {
881 devState = Prepare_Data_In;
882 cmdReg.status |= STATUS_BSY_BIT;
883 }
884 }
885 }
886 break;
887
888 case Prepare_Data_Out:
889 if (action == ACT_CMD_ERROR || cmdBytesLeft == 0) {
890 // clear the BSY bit
891 setComplete();
892
893 if (!isIENSet()) {
894 devState = Device_Idle_SI;
895 intrPost();
896 } else {
897 devState = Device_Idle_S;
898 }
899 } else if (cmdBytesLeft != 0) {
900 // clear the BSY bit
901 cmdReg.status &= ~STATUS_BSY_BIT;
902 // set the DRQ bit
903 cmdReg.status |= STATUS_DRQ_BIT;
904
905 // clear the data buffer to get it ready for writes
906 memset(dataBuffer, 0, MAX_DMA_SIZE);
907
908 if (!isIENSet()) {
909 devState = Data_Ready_INTRQ_Out;
910 intrPost();
911 } else {
912 devState = Transfer_Data_Out;
913 }
914 }
915 break;
916
917 case Data_Ready_INTRQ_Out:
918 if (action == ACT_STAT_READ) {
919 devState = Transfer_Data_Out;
920 intrClear();
921 }
922 break;
923
924 case Transfer_Data_Out:
925 if (action == ACT_DATA_WRITE_BYTE ||
926 action == ACT_DATA_WRITE_SHORT) {
927
928 if (action == ACT_DATA_READ_BYTE) {
929 panic("DEBUG: WRITING DATA ONE BYTE AT A TIME!\n");
930 } else {
931 // copy the latest short into the data buffer
932 memcpy((void *)&dataBuffer[SectorSize - drqBytesLeft],
933 (void *)&cmdReg.data0,
934 sizeof(uint16_t));
935
936 drqBytesLeft -= 2;
937 cmdBytesLeft -= 2;
938 }
939
940 if (drqBytesLeft == 0) {
941 // copy the block to the disk
942 writeDisk(curSector++, dataBuffer);
943
944 // set the BSY bit
945 cmdReg.status |= STATUS_BSY_BIT;
946 // clear the DRQ bit
947 cmdReg.status &= ~STATUS_DRQ_BIT;
948
949 devState = Prepare_Data_Out;
950 }
951 }
952 break;
953
954 case Prepare_Data_Dma:
955 if (action == ACT_CMD_ERROR) {
956 // clear the BSY bit
957 setComplete();
958
959 if (!isIENSet()) {
960 devState = Device_Idle_SI;
961 intrPost();
962 } else {
963 devState = Device_Idle_S;
964 }
965 } else if (action == ACT_DMA_READY) {
966 // clear the BSY bit
967 cmdReg.status &= ~STATUS_BSY_BIT;
968 // set the DRQ bit
969 cmdReg.status |= STATUS_DRQ_BIT;
970
971 devState = Transfer_Data_Dma;
972
973 if (dmaState != Dma_Idle)
974 panic("Inconsistent DMA state, should be Dma_Idle\n");
975
976 dmaState = Dma_Start;
977 // wait for the write to the DMA start bit
978 }
979 break;
980
981 case Transfer_Data_Dma:
982 if (action == ACT_CMD_ERROR || action == ACT_DMA_DONE) {
983 // clear the BSY bit
984 setComplete();
985 // set the seek bit
986 cmdReg.status |= 0x10;
987 // clear the controller state for DMA transfer
988 ctrl->setDmaComplete(this);
989
990 if (!isIENSet()) {
991 devState = Device_Idle_SI;
992 intrPost();
993 } else {
994 devState = Device_Idle_S;
995 }
996 }
997 break;
998
999 default:
1000 panic("Unknown IDE device state: %#x\n", devState);
1001 }
1002 }
1003
1004 void
1005 IdeDisk::serialize(ostream &os)
1006 {
1007 // Check all outstanding events to see if they are scheduled
1008 // these are all mutually exclusive
1009 Tick reschedule = 0;
1010 Events_t event = None;
1011
1012 if (dmaTransferEvent.scheduled()) {
1013 reschedule = dmaTransferEvent.when();
1014 event = Transfer;
1015 } else if (dmaReadWaitEvent.scheduled()) {
1016 reschedule = dmaReadWaitEvent.when();
1017 event = ReadWait;
1018 } else if (dmaWriteWaitEvent.scheduled()) {
1019 reschedule = dmaWriteWaitEvent.when();
1020 event = WriteWait;
1021 } else if (dmaPrdReadEvent.scheduled()) {
1022 reschedule = dmaPrdReadEvent.when();
1023 event = PrdRead;
1024 } else if (dmaReadEvent.scheduled()) {
1025 reschedule = dmaReadEvent.when();
1026 event = DmaRead;
1027 } else if (dmaWriteEvent.scheduled()) {
1028 reschedule = dmaWriteEvent.when();
1029 event = DmaWrite;
1030 }
1031
1032 SERIALIZE_SCALAR(reschedule);
1033 SERIALIZE_ENUM(event);
1034
1035 // Serialize device registers
1036 SERIALIZE_SCALAR(cmdReg.data0);
1037 SERIALIZE_SCALAR(cmdReg.data1);
1038 SERIALIZE_SCALAR(cmdReg.sec_count);
1039 SERIALIZE_SCALAR(cmdReg.sec_num);
1040 SERIALIZE_SCALAR(cmdReg.cyl_low);
1041 SERIALIZE_SCALAR(cmdReg.cyl_high);
1042 SERIALIZE_SCALAR(cmdReg.drive);
1043 SERIALIZE_SCALAR(cmdReg.status);
1044 SERIALIZE_SCALAR(nIENBit);
1045 SERIALIZE_SCALAR(devID);
1046
1047 // Serialize the PRD related information
1048 SERIALIZE_SCALAR(curPrd.entry.baseAddr);
1049 SERIALIZE_SCALAR(curPrd.entry.byteCount);
1050 SERIALIZE_SCALAR(curPrd.entry.endOfTable);
1051 SERIALIZE_SCALAR(curPrdAddr);
1052
1053 // Serialize current transfer related information
1054 SERIALIZE_SCALAR(cmdBytesLeft);
1055 SERIALIZE_SCALAR(drqBytesLeft);
1056 SERIALIZE_SCALAR(curSector);
1057 SERIALIZE_SCALAR(curCommand);
1058 SERIALIZE_SCALAR(dmaRead);
1059 SERIALIZE_SCALAR(dmaInterfaceBytes);
1060 SERIALIZE_SCALAR(intrPending);
1061 SERIALIZE_ENUM(devState);
1062 SERIALIZE_ENUM(dmaState);
1063 SERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1064 }
1065
1066 void
1067 IdeDisk::unserialize(Checkpoint *cp, const string &section)
1068 {
1069 // Reschedule events that were outstanding
1070 // these are all mutually exclusive
1071 Tick reschedule = 0;
1072 Events_t event = None;
1073
1074 UNSERIALIZE_SCALAR(reschedule);
1075 UNSERIALIZE_ENUM(event);
1076
1077 switch (event) {
1078 case None : break;
1079 case Transfer : dmaTransferEvent.schedule(reschedule); break;
1080 case ReadWait : dmaReadWaitEvent.schedule(reschedule); break;
1081 case WriteWait : dmaWriteWaitEvent.schedule(reschedule); break;
1082 case PrdRead : dmaPrdReadEvent.schedule(reschedule); break;
1083 case DmaRead : dmaReadEvent.schedule(reschedule); break;
1084 case DmaWrite : dmaWriteEvent.schedule(reschedule); break;
1085 }
1086
1087 // Unserialize device registers
1088 UNSERIALIZE_SCALAR(cmdReg.data0);
1089 UNSERIALIZE_SCALAR(cmdReg.data1);
1090 UNSERIALIZE_SCALAR(cmdReg.sec_count);
1091 UNSERIALIZE_SCALAR(cmdReg.sec_num);
1092 UNSERIALIZE_SCALAR(cmdReg.cyl_low);
1093 UNSERIALIZE_SCALAR(cmdReg.cyl_high);
1094 UNSERIALIZE_SCALAR(cmdReg.drive);
1095 UNSERIALIZE_SCALAR(cmdReg.status);
1096 UNSERIALIZE_SCALAR(nIENBit);
1097 UNSERIALIZE_SCALAR(devID);
1098
1099 // Unserialize the PRD related information
1100 UNSERIALIZE_SCALAR(curPrd.entry.baseAddr);
1101 UNSERIALIZE_SCALAR(curPrd.entry.byteCount);
1102 UNSERIALIZE_SCALAR(curPrd.entry.endOfTable);
1103 UNSERIALIZE_SCALAR(curPrdAddr);
1104
1105 // Unserialize current transfer related information
1106 UNSERIALIZE_SCALAR(cmdBytesLeft);
1107 UNSERIALIZE_SCALAR(drqBytesLeft);
1108 UNSERIALIZE_SCALAR(curSector);
1109 UNSERIALIZE_SCALAR(curCommand);
1110 UNSERIALIZE_SCALAR(dmaRead);
1111 UNSERIALIZE_SCALAR(dmaInterfaceBytes);
1112 UNSERIALIZE_SCALAR(intrPending);
1113 UNSERIALIZE_ENUM(devState);
1114 UNSERIALIZE_ENUM(dmaState);
1115 UNSERIALIZE_ARRAY(dataBuffer, MAX_DMA_SIZE);
1116 }
1117
1118 #ifndef DOXYGEN_SHOULD_SKIP_THIS
1119
1120 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
1121
1122 SimObjectParam<DiskImage *> image;
1123 SimObjectParam<PhysicalMemory *> physmem;
1124 Param<int> driveID;
1125 Param<int> disk_delay;
1126
1127 END_DECLARE_SIM_OBJECT_PARAMS(IdeDisk)
1128
1129 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeDisk)
1130
1131 INIT_PARAM(image, "Disk image"),
1132 INIT_PARAM(physmem, "Physical memory"),
1133 INIT_PARAM(driveID, "Drive ID (0=master 1=slave)"),
1134 INIT_PARAM_DFLT(disk_delay, "Fixed disk delay in microseconds", 1)
1135
1136 END_INIT_SIM_OBJECT_PARAMS(IdeDisk)
1137
1138
1139 CREATE_SIM_OBJECT(IdeDisk)
1140 {
1141 return new IdeDisk(getInstanceName(), image, physmem, driveID,
1142 disk_delay);
1143 }
1144
1145 REGISTER_SIM_OBJECT("IdeDisk", IdeDisk)
1146
1147 #endif //DOXYGEN_SHOULD_SKIP_THIS