ide_ctrl.cc revision 2665
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
50using namespace std;
51
52////
53// Initialization and destruction
54////
55
56IdeController::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
107IdeController::~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
118void
119IdeController::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
152int
153IdeController::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
170int
171IdeController::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
180bool
181IdeController::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
200void
201IdeController::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
230void
231IdeController::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
269void
270IdeController::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
301void
302IdeController::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}
311void
312IdeController::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
344void
345IdeController::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
390void
391IdeController::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
429Tick
430IdeController::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
515Tick
516IdeController::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
702void
703IdeController::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
734void
735IdeController::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
769BEGIN_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
781END_DECLARE_SIM_OBJECT_PARAMS(IdeController)
782
783BEGIN_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
795END_INIT_SIM_OBJECT_PARAMS(IdeController)
796
797CREATE_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
813REGISTER_SIM_OBJECT("IdeController", IdeController)
814
815#endif //DOXYGEN_SHOULD_SKIP_THIS
816