Merge zizzer:/bk/newmem
[gem5.git] / src / dev / ide_ctrl.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 * Authors: Andrew Schultz
29 * Ali Saidi
30 * Miguel Serrano
31 */
32
33 #include <cstddef>
34 #include <cstdlib>
35 #include <string>
36 #include <vector>
37
38 #include "base/trace.hh"
39 #include "cpu/intr_control.hh"
40 #include "dev/ide_ctrl.hh"
41 #include "dev/ide_disk.hh"
42 #include "dev/pciconfigall.hh"
43 #include "dev/pcireg.h"
44 #include "dev/platform.hh"
45 #include "mem/packet.hh"
46 #include "sim/builder.hh"
47 #include "sim/sim_object.hh"
48 #include "sim/byteswap.hh"
49
50 using namespace std;
51
52 ////
53 // Initialization and destruction
54 ////
55
56 IdeController::IdeController(Params *p)
57 : PciDev(p)
58 {
59 // initialize the PIO interface addresses
60 pri_cmd_addr = 0;
61 pri_cmd_size = BARSize[0];
62
63 pri_ctrl_addr = 0;
64 pri_ctrl_size = BARSize[1];
65
66 sec_cmd_addr = 0;
67 sec_cmd_size = BARSize[2];
68
69 sec_ctrl_addr = 0;
70 sec_ctrl_size = BARSize[3];
71
72 // initialize the bus master interface (BMI) address to be configured
73 // via PCI
74 bmi_addr = 0;
75 bmi_size = BARSize[4];
76
77 // zero out all of the registers
78 memset(bmi_regs.data, 0, sizeof(bmi_regs));
79 memset(config_regs.data, 0, sizeof(config_regs.data));
80
81 // setup initial values
82 // enable both channels
83 config_regs.idetim0 = htole((uint16_t)IDETIM_DECODE_EN);
84 config_regs.idetim1 = htole((uint16_t)IDETIM_DECODE_EN);
85 bmi_regs.bmis0 = DMA1CAP | DMA0CAP;
86 bmi_regs.bmis1 = DMA1CAP | DMA0CAP;
87
88 // reset all internal variables
89 io_enabled = false;
90 bm_enabled = false;
91 memset(cmd_in_progress, 0, sizeof(cmd_in_progress));
92
93 // setup the disks attached to controller
94 memset(disks, 0, sizeof(disks));
95 dev[0] = 0;
96 dev[1] = 0;
97
98 if (params()->disks.size() > 3)
99 panic("IDE controllers support a maximum of 4 devices attached!\n");
100
101 for (int i = 0; i < params()->disks.size(); i++) {
102 disks[i] = params()->disks[i];
103 disks[i]->setController(this);
104 }
105 }
106
107 IdeController::~IdeController()
108 {
109 for (int i = 0; i < 4; i++)
110 if (disks[i])
111 delete disks[i];
112 }
113
114 ////
115 // Utility functions
116 ///
117
118 void
119 IdeController::parseAddr(const Addr &addr, Addr &offset, IdeChannel &channel,
120 IdeRegType &reg_type)
121 {
122 offset = addr;
123
124 if (addr >= pri_cmd_addr && addr < (pri_cmd_addr + pri_cmd_size)) {
125 offset -= pri_cmd_addr;
126 reg_type = COMMAND_BLOCK;
127 channel = PRIMARY;
128 } else if (addr >= pri_ctrl_addr &&
129 addr < (pri_ctrl_addr + pri_ctrl_size)) {
130 offset -= pri_ctrl_addr;
131 reg_type = CONTROL_BLOCK;
132 channel = PRIMARY;
133 } else if (addr >= sec_cmd_addr &&
134 addr < (sec_cmd_addr + sec_cmd_size)) {
135 offset -= sec_cmd_addr;
136 reg_type = COMMAND_BLOCK;
137 channel = SECONDARY;
138 } else if (addr >= sec_ctrl_addr &&
139 addr < (sec_ctrl_addr + sec_ctrl_size)) {
140 offset -= sec_ctrl_addr;
141 reg_type = CONTROL_BLOCK;
142 channel = SECONDARY;
143 } else if (addr >= bmi_addr && addr < (bmi_addr + bmi_size)) {
144 offset -= bmi_addr;
145 reg_type = BMI_BLOCK;
146 channel = (offset < BMIC1) ? PRIMARY : SECONDARY;
147 } else {
148 panic("IDE controller access to invalid address: %#x\n", addr);
149 }
150 }
151
152 int
153 IdeController::getDisk(IdeChannel channel)
154 {
155 int disk = 0;
156 uint8_t *devBit = &dev[0];
157
158 if (channel == SECONDARY) {
159 disk += 2;
160 devBit = &dev[1];
161 }
162
163 disk += *devBit;
164
165 assert(*devBit == 0 || *devBit == 1);
166
167 return disk;
168 }
169
170 int
171 IdeController::getDisk(IdeDisk *diskPtr)
172 {
173 for (int i = 0; i < 4; i++) {
174 if ((long)diskPtr == (long)disks[i])
175 return i;
176 }
177 return -1;
178 }
179
180 bool
181 IdeController::isDiskSelected(IdeDisk *diskPtr)
182 {
183 for (int i = 0; i < 4; i++) {
184 if ((long)diskPtr == (long)disks[i]) {
185 // is disk is on primary or secondary channel
186 int channel = i/2;
187 // is disk the master or slave
188 int devID = i%2;
189
190 return (dev[channel] == devID);
191 }
192 }
193 panic("Unable to find disk by pointer!!\n");
194 }
195
196 ////
197 // Command completion
198 ////
199
200 void
201 IdeController::setDmaComplete(IdeDisk *disk)
202 {
203 int diskNum = getDisk(disk);
204
205 if (diskNum < 0)
206 panic("Unable to find disk based on pointer %#x\n", disk);
207
208 if (diskNum < 2) {
209 // clear the start/stop bit in the command register
210 bmi_regs.bmic0 &= ~SSBM;
211 // clear the bus master active bit in the status register
212 bmi_regs.bmis0 &= ~BMIDEA;
213 // set the interrupt bit
214 bmi_regs.bmis0 |= IDEINTS;
215 } else {
216 // clear the start/stop bit in the command register
217 bmi_regs.bmic1 &= ~SSBM;
218 // clear the bus master active bit in the status register
219 bmi_regs.bmis1 &= ~BMIDEA;
220 // set the interrupt bit
221 bmi_regs.bmis1 |= IDEINTS;
222 }
223 }
224
225
226 ////
227 // Read and write handling
228 ////
229
230 void
231 IdeController::readConfig(int offset, uint8_t *data)
232 {
233 if (offset < PCI_DEVICE_SPECIFIC) {
234 PciDev::readConfig(offset, data);
235 } else if (offset >= IDE_CTRL_CONF_START &&
236 (offset + 1) <= IDE_CTRL_CONF_END) {
237
238 switch (offset) {
239 case IDE_CTRL_CONF_DEV_TIMING:
240 *data = config_regs.sidetim;
241 break;
242 case IDE_CTRL_CONF_UDMA_CNTRL:
243 *data = config_regs.udmactl;
244 break;
245 case IDE_CTRL_CONF_PRIM_TIMING+1:
246 *data = htole(config_regs.idetim0) >> 8;
247 break;
248 case IDE_CTRL_CONF_SEC_TIMING+1:
249 *data = htole(config_regs.idetim1) >> 8;
250 break;
251 case IDE_CTRL_CONF_IDE_CONFIG:
252 *data = htole(config_regs.ideconfig) & 0xFF;
253 break;
254 case IDE_CTRL_CONF_IDE_CONFIG+1:
255 *data = htole(config_regs.ideconfig) >> 8;
256 break;
257 default:
258 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
259 offset);
260 }
261
262 } else {
263 panic("Read of unimplemented PCI config. register: %x\n", offset);
264 }
265 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n",
266 offset, (uint32_t)*data);
267 }
268
269 void
270 IdeController::readConfig(int offset, uint16_t *data)
271 {
272 if (offset < PCI_DEVICE_SPECIFIC) {
273 PciDev::readConfig(offset, data);
274 } else if (offset >= IDE_CTRL_CONF_START &&
275 (offset + 2) <= IDE_CTRL_CONF_END) {
276
277 switch (offset) {
278 case IDE_CTRL_CONF_PRIM_TIMING:
279 *data = config_regs.idetim0;
280 break;
281 case IDE_CTRL_CONF_SEC_TIMING:
282 *data = config_regs.idetim1;
283 break;
284 case IDE_CTRL_CONF_UDMA_TIMING:
285 *data = config_regs.udmatim;
286 break;
287 case IDE_CTRL_CONF_IDE_CONFIG:
288 *data = config_regs.ideconfig;
289 break;
290 default:
291 panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
292 offset);
293 }
294
295 } else {
296 panic("Read of unimplemented PCI config. register: %x\n", offset);
297 }
298 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset, *data);
299 }
300
301 void
302 IdeController::readConfig(int offset, uint32_t *data)
303 {
304 if (offset < PCI_DEVICE_SPECIFIC) {
305 PciDev::readConfig(offset, data);
306 } else {
307 panic("Read of unimplemented PCI config. register: %x\n", offset);
308 }
309 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset, *data);
310 }
311 void
312 IdeController::writeConfig(int offset, const uint8_t data)
313 {
314 if (offset < PCI_DEVICE_SPECIFIC) {
315 PciDev::writeConfig(offset, data);
316 } else if (offset >= IDE_CTRL_CONF_START &&
317 (offset + 1) <= IDE_CTRL_CONF_END) {
318
319 switch (offset) {
320 case IDE_CTRL_CONF_DEV_TIMING:
321 config_regs.sidetim = data;
322 break;
323 case IDE_CTRL_CONF_UDMA_CNTRL:
324 config_regs.udmactl = data;
325 break;
326 case IDE_CTRL_CONF_IDE_CONFIG:
327 config_regs.ideconfig = (config_regs.ideconfig & 0xFF00) | (data);
328 break;
329 case IDE_CTRL_CONF_IDE_CONFIG+1:
330 config_regs.ideconfig = (config_regs.ideconfig & 0x00FF) | data << 8;
331 break;
332 default:
333 panic("Invalid PCI configuration write for size 1 offset: %#x!\n",
334 offset);
335 }
336
337 } else {
338 panic("Read of unimplemented PCI config. register: %x\n", offset);
339 }
340 DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
341 offset, (uint32_t)data);
342 }
343
344 void
345 IdeController::writeConfig(int offset, const uint16_t data)
346 {
347 if (offset < PCI_DEVICE_SPECIFIC) {
348 PciDev::writeConfig(offset, data);
349 } else if (offset >= IDE_CTRL_CONF_START &&
350 (offset + 2) <= IDE_CTRL_CONF_END) {
351
352 switch (offset) {
353 case IDE_CTRL_CONF_PRIM_TIMING:
354 config_regs.idetim0 = data;
355 break;
356 case IDE_CTRL_CONF_SEC_TIMING:
357 config_regs.idetim1 = data;
358 break;
359 case IDE_CTRL_CONF_UDMA_TIMING:
360 config_regs.udmatim = data;
361 break;
362 case IDE_CTRL_CONF_IDE_CONFIG:
363 config_regs.ideconfig = data;
364 break;
365 default:
366 panic("Invalid PCI configuration write for size 2 offset: %#x!\n",
367 offset);
368 }
369
370 } else {
371 panic("Write of unimplemented PCI config. register: %x\n", offset);
372 }
373 DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", offset, data);
374
375 /* Trap command register writes and enable IO/BM as appropriate. */
376 if (offset == PCI_COMMAND) {
377 if (letoh(config.command) & PCI_CMD_IOSE)
378 io_enabled = true;
379 else
380 io_enabled = false;
381
382 if (letoh(config.command) & PCI_CMD_BME)
383 bm_enabled = true;
384 else
385 bm_enabled = false;
386 }
387
388 }
389
390 void
391 IdeController::writeConfig(int offset, const uint32_t data)
392 {
393 if (offset < PCI_DEVICE_SPECIFIC) {
394 PciDev::writeConfig(offset, data);
395 } else {
396 panic("Read of unimplemented PCI config. register: %x\n", offset);
397 }
398
399 DPRINTF(IdeCtrl, "PCI write offset: %#x size: 4 data: %#x\n", offset, data);
400
401 switch(offset) {
402 case PCI0_BASE_ADDR0:
403 if (BARAddrs[0] != 0)
404 pri_cmd_addr = BARAddrs[0];
405 break;
406
407 case PCI0_BASE_ADDR1:
408 if (BARAddrs[1] != 0)
409 pri_ctrl_addr = BARAddrs[1];
410 break;
411
412 case PCI0_BASE_ADDR2:
413 if (BARAddrs[2] != 0)
414 sec_cmd_addr = BARAddrs[2];
415 break;
416
417 case PCI0_BASE_ADDR3:
418 if (BARAddrs[3] != 0)
419 sec_ctrl_addr = BARAddrs[3];
420 break;
421
422 case PCI0_BASE_ADDR4:
423 if (BARAddrs[4] != 0)
424 bmi_addr = BARAddrs[4];
425 break;
426 }
427 }
428
429 Tick
430 IdeController::read(Packet *pkt)
431 {
432 Addr offset;
433 IdeChannel channel;
434 IdeRegType reg_type;
435 int disk;
436
437 pkt->allocate();
438 if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
439 panic("Bad IDE read size: %d\n", pkt->getSize());
440
441 parseAddr(pkt->getAddr(), offset, channel, reg_type);
442
443 if (!io_enabled) {
444 pkt->result = Packet::Success;
445 return pioDelay;
446 }
447
448 switch (reg_type) {
449 case BMI_BLOCK:
450 switch (pkt->getSize()) {
451 case sizeof(uint8_t):
452 pkt->set(bmi_regs.data[offset]);
453 break;
454 case sizeof(uint16_t):
455 pkt->set(*(uint16_t*)&bmi_regs.data[offset]);
456 break;
457 case sizeof(uint32_t):
458 pkt->set(*(uint32_t*)&bmi_regs.data[offset]);
459 break;
460 default:
461 panic("IDE read of BMI reg invalid size: %#x\n", pkt->getSize());
462 }
463 break;
464
465 case COMMAND_BLOCK:
466 case CONTROL_BLOCK:
467 disk = getDisk(channel);
468
469 if (disks[disk] == NULL) {
470 pkt->set<uint8_t>(0);
471 break;
472 }
473
474 switch (offset) {
475 case DATA_OFFSET:
476 switch (pkt->getSize()) {
477 case sizeof(uint16_t):
478 disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
479 break;
480
481 case sizeof(uint32_t):
482 disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
483 disks[disk]->read(offset, reg_type,
484 pkt->getPtr<uint8_t>() + sizeof(uint16_t));
485 break;
486
487 default:
488 panic("IDE read of data reg invalid size: %#x\n", pkt->getSize());
489 }
490 break;
491 default:
492 if (pkt->getSize() == sizeof(uint8_t)) {
493 disks[disk]->read(offset, reg_type, pkt->getPtr<uint8_t>());
494 } else
495 panic("IDE read of command reg of invalid size: %#x\n", pkt->getSize());
496 }
497 break;
498 default:
499 panic("IDE controller read of unknown register block type!\n");
500 }
501 if (pkt->getSize() == 1)
502 DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
503 offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>());
504 else if (pkt->getSize() == 2)
505 DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
506 offset, pkt->getSize(), pkt->get<uint16_t>());
507 else
508 DPRINTF(IdeCtrl, "read from offset: %#x size: %#x data: %#x\n",
509 offset, pkt->getSize(), pkt->get<uint32_t>());
510
511 pkt->result = Packet::Success;
512 return pioDelay;
513 }
514
515 Tick
516 IdeController::write(Packet *pkt)
517 {
518 Addr offset;
519 IdeChannel channel;
520 IdeRegType reg_type;
521 int disk;
522 uint8_t oldVal, newVal;
523
524 parseAddr(pkt->getAddr(), offset, channel, reg_type);
525
526 if (!io_enabled) {
527 pkt->result = Packet::Success;
528 DPRINTF(IdeCtrl, "io not enabled\n");
529 return pioDelay;
530 }
531
532 switch (reg_type) {
533 case BMI_BLOCK:
534 if (!bm_enabled) {
535 pkt->result = Packet::Success;
536 return pioDelay;
537 }
538
539 switch (offset) {
540 // Bus master IDE command register
541 case BMIC1:
542 case BMIC0:
543 if (pkt->getSize() != sizeof(uint8_t))
544 panic("Invalid BMIC write size: %x\n", pkt->getSize());
545
546 // select the current disk based on DEV bit
547 disk = getDisk(channel);
548
549 oldVal = bmi_regs.chan[channel].bmic;
550 newVal = pkt->get<uint8_t>();
551
552 // if a DMA transfer is in progress, R/W control cannot change
553 if (oldVal & SSBM) {
554 if ((oldVal & RWCON) ^ (newVal & RWCON)) {
555 (oldVal & RWCON) ? newVal |= RWCON : newVal &= ~RWCON;
556 }
557 }
558
559 // see if the start/stop bit is being changed
560 if ((oldVal & SSBM) ^ (newVal & SSBM)) {
561 if (oldVal & SSBM) {
562 // stopping DMA transfer
563 DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
564
565 // clear the BMIDEA bit
566 bmi_regs.chan[channel].bmis =
567 bmi_regs.chan[channel].bmis & ~BMIDEA;
568
569 if (disks[disk] == NULL)
570 panic("DMA stop for disk %d which does not exist\n",
571 disk);
572
573 // inform the disk of the DMA transfer abort
574 disks[disk]->abortDma();
575 } else {
576 // starting DMA transfer
577 DPRINTF(IdeCtrl, "Starting DMA transfer\n");
578
579 // set the BMIDEA bit
580 bmi_regs.chan[channel].bmis =
581 bmi_regs.chan[channel].bmis | BMIDEA;
582
583 if (disks[disk] == NULL)
584 panic("DMA start for disk %d which does not exist\n",
585 disk);
586
587 // inform the disk of the DMA transfer start
588 disks[disk]->startDma(letoh(bmi_regs.chan[channel].bmidtp));
589 }
590 }
591
592 // update the register value
593 bmi_regs.chan[channel].bmic = newVal;
594 break;
595
596 // Bus master IDE status register
597 case BMIS0:
598 case BMIS1:
599 if (pkt->getSize() != sizeof(uint8_t))
600 panic("Invalid BMIS write size: %x\n", pkt->getSize());
601
602 oldVal = bmi_regs.chan[channel].bmis;
603 newVal = pkt->get<uint8_t>();
604
605 // the BMIDEA bit is RO
606 newVal |= (oldVal & BMIDEA);
607
608 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
609 if ((oldVal & IDEINTS) && (newVal & IDEINTS))
610 newVal &= ~IDEINTS; // clear the interrupt?
611 else
612 (oldVal & IDEINTS) ? newVal |= IDEINTS : newVal &= ~IDEINTS;
613
614 if ((oldVal & IDEDMAE) && (newVal & IDEDMAE))
615 newVal &= ~IDEDMAE;
616 else
617 (oldVal & IDEDMAE) ? newVal |= IDEDMAE : newVal &= ~IDEDMAE;
618
619 bmi_regs.chan[channel].bmis = newVal;
620 break;
621
622 // Bus master IDE descriptor table pointer register
623 case BMIDTP0:
624 case BMIDTP1:
625 {
626 if (pkt->getSize() != sizeof(uint32_t))
627 panic("Invalid BMIDTP write size: %x\n", pkt->getSize());
628
629 bmi_regs.chan[channel].bmidtp = htole(pkt->get<uint32_t>() & ~0x3);
630 }
631 break;
632
633 default:
634 if (pkt->getSize() != sizeof(uint8_t) &&
635 pkt->getSize() != sizeof(uint16_t) &&
636 pkt->getSize() != sizeof(uint32_t))
637 panic("IDE controller write of invalid write size: %x\n",
638 pkt->getSize());
639
640 // do a default copy of data into the registers
641 memcpy(&bmi_regs.data[offset], pkt->getPtr<uint8_t>(), pkt->getSize());
642 }
643 break;
644 case COMMAND_BLOCK:
645 if (offset == IDE_SELECT_OFFSET) {
646 uint8_t *devBit = &dev[channel];
647 *devBit = (letoh(pkt->get<uint8_t>()) & IDE_SELECT_DEV_BIT) ? 1 : 0;
648 }
649 // fall-through ok!
650 case CONTROL_BLOCK:
651 disk = getDisk(channel);
652
653 if (disks[disk] == NULL)
654 break;
655
656 switch (offset) {
657 case DATA_OFFSET:
658 switch (pkt->getSize()) {
659 case sizeof(uint16_t):
660 disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
661 break;
662
663 case sizeof(uint32_t):
664 disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
665 disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>() +
666 sizeof(uint16_t));
667 break;
668 default:
669 panic("IDE write of data reg invalid size: %#x\n", pkt->getSize());
670 }
671 break;
672 default:
673 if (pkt->getSize() == sizeof(uint8_t)) {
674 disks[disk]->write(offset, reg_type, pkt->getPtr<uint8_t>());
675 } else
676 panic("IDE write of command reg of invalid size: %#x\n", pkt->getSize());
677 }
678 break;
679 default:
680 panic("IDE controller write of unknown register block type!\n");
681 }
682
683 if (pkt->getSize() == 1)
684 DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
685 offset, pkt->getSize(), (uint32_t)pkt->get<uint8_t>());
686 else if (pkt->getSize() == 2)
687 DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
688 offset, pkt->getSize(), pkt->get<uint16_t>());
689 else
690 DPRINTF(IdeCtrl, "write to offset: %#x size: %#x data: %#x\n",
691 offset, pkt->getSize(), pkt->get<uint32_t>());
692
693
694 pkt->result = Packet::Success;
695 return pioDelay;
696 }
697
698 ////
699 // Serialization
700 ////
701
702 void
703 IdeController::serialize(std::ostream &os)
704 {
705 // Serialize the PciDev base class
706 PciDev::serialize(os);
707
708 // Serialize register addresses and sizes
709 SERIALIZE_SCALAR(pri_cmd_addr);
710 SERIALIZE_SCALAR(pri_cmd_size);
711 SERIALIZE_SCALAR(pri_ctrl_addr);
712 SERIALIZE_SCALAR(pri_ctrl_size);
713 SERIALIZE_SCALAR(sec_cmd_addr);
714 SERIALIZE_SCALAR(sec_cmd_size);
715 SERIALIZE_SCALAR(sec_ctrl_addr);
716 SERIALIZE_SCALAR(sec_ctrl_size);
717 SERIALIZE_SCALAR(bmi_addr);
718 SERIALIZE_SCALAR(bmi_size);
719
720 // Serialize registers
721 SERIALIZE_ARRAY(bmi_regs.data,
722 sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));
723 SERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));
724 SERIALIZE_ARRAY(config_regs.data,
725 sizeof(config_regs.data) / sizeof(config_regs.data[0]));
726
727 // Serialize internal state
728 SERIALIZE_SCALAR(io_enabled);
729 SERIALIZE_SCALAR(bm_enabled);
730 SERIALIZE_ARRAY(cmd_in_progress,
731 sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
732 }
733
734 void
735 IdeController::unserialize(Checkpoint *cp, const std::string &section)
736 {
737 // Unserialize the PciDev base class
738 PciDev::unserialize(cp, section);
739
740 // Unserialize register addresses and sizes
741 UNSERIALIZE_SCALAR(pri_cmd_addr);
742 UNSERIALIZE_SCALAR(pri_cmd_size);
743 UNSERIALIZE_SCALAR(pri_ctrl_addr);
744 UNSERIALIZE_SCALAR(pri_ctrl_size);
745 UNSERIALIZE_SCALAR(sec_cmd_addr);
746 UNSERIALIZE_SCALAR(sec_cmd_size);
747 UNSERIALIZE_SCALAR(sec_ctrl_addr);
748 UNSERIALIZE_SCALAR(sec_ctrl_size);
749 UNSERIALIZE_SCALAR(bmi_addr);
750 UNSERIALIZE_SCALAR(bmi_size);
751
752 // Unserialize registers
753 UNSERIALIZE_ARRAY(bmi_regs.data,
754 sizeof(bmi_regs.data) / sizeof(bmi_regs.data[0]));
755 UNSERIALIZE_ARRAY(dev, sizeof(dev) / sizeof(dev[0]));
756 UNSERIALIZE_ARRAY(config_regs.data,
757 sizeof(config_regs.data) / sizeof(config_regs.data[0]));
758
759 // Unserialize internal state
760 UNSERIALIZE_SCALAR(io_enabled);
761 UNSERIALIZE_SCALAR(bm_enabled);
762 UNSERIALIZE_ARRAY(cmd_in_progress,
763 sizeof(cmd_in_progress) / sizeof(cmd_in_progress[0]));
764 pioPort->sendStatusChange(Port::RangeChange);
765 }
766
767 #ifndef DOXYGEN_SHOULD_SKIP_THIS
768
769 BEGIN_DECLARE_SIM_OBJECT_PARAMS(IdeController)
770
771 SimObjectParam<System *> system;
772 SimObjectParam<Platform *> platform;
773 SimObjectParam<PciConfigAll *> configspace;
774 SimObjectParam<PciConfigData *> configdata;
775 Param<uint32_t> pci_bus;
776 Param<uint32_t> pci_dev;
777 Param<uint32_t> pci_func;
778 Param<Tick> pio_latency;
779 SimObjectVectorParam<IdeDisk *> disks;
780
781 END_DECLARE_SIM_OBJECT_PARAMS(IdeController)
782
783 BEGIN_INIT_SIM_OBJECT_PARAMS(IdeController)
784
785 INIT_PARAM(system, "System pointer"),
786 INIT_PARAM(platform, "Platform pointer"),
787 INIT_PARAM(configspace, "PCI Configspace"),
788 INIT_PARAM(configdata, "PCI Config data"),
789 INIT_PARAM(pci_bus, "PCI bus ID"),
790 INIT_PARAM(pci_dev, "PCI device number"),
791 INIT_PARAM(pci_func, "PCI function code"),
792 INIT_PARAM_DFLT(pio_latency, "Programmed IO latency in bus cycles", 1),
793 INIT_PARAM(disks, "IDE disks attached to this controller")
794
795 END_INIT_SIM_OBJECT_PARAMS(IdeController)
796
797 CREATE_SIM_OBJECT(IdeController)
798 {
799 IdeController::Params *params = new IdeController::Params;
800 params->name = getInstanceName();
801 params->platform = platform;
802 params->system = system;
803 params->configSpace = configspace;
804 params->configData = configdata;
805 params->busNum = pci_bus;
806 params->deviceNum = pci_dev;
807 params->functionNum = pci_func;
808 params->pio_delay = pio_latency;
809 params->disks = disks;
810 return new IdeController(params);
811 }
812
813 REGISTER_SIM_OBJECT("IdeController", IdeController)
814
815 #endif //DOXYGEN_SHOULD_SKIP_THIS