2 * Copyright (c) 2004-2005 The Regents of The University of Michigan
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.
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.
28 * Authors: Andrew Schultz
35 #include "base/trace.hh"
36 #include "cpu/intr_control.hh"
37 #include "dev/ide_ctrl.hh"
38 #include "dev/ide_disk.hh"
39 #include "mem/packet.hh"
40 #include "mem/packet_access.hh"
41 #include "params/IdeController.hh"
42 #include "sim/byteswap.hh"
46 // Bus master IDE registers
53 // PCI config space registers
56 SecondaryTiming
= 0x42,
63 static const uint16_t timeRegWithDecodeEn
= 0x8000;
65 IdeController::Channel::Channel(
66 string newName
, Addr _cmdSize
, Addr _ctrlSize
) :
68 cmdAddr(0), cmdSize(_cmdSize
), ctrlAddr(0), ctrlSize(_ctrlSize
),
69 master(NULL
), slave(NULL
), selected(NULL
)
71 memset(&bmiRegs
, 0, sizeof(bmiRegs
));
72 bmiRegs
.status
.dmaCap0
= 1;
73 bmiRegs
.status
.dmaCap1
= 1;
76 IdeController::Channel::~Channel()
82 IdeController::IdeController(Params
*p
)
83 : PciDev(p
), primary(name() + ".primary", BARSize
[0], BARSize
[1]),
84 secondary(name() + ".secondary", BARSize
[2], BARSize
[3]),
85 bmiAddr(0), bmiSize(BARSize
[4]),
86 primaryTiming(htole(timeRegWithDecodeEn
)),
87 secondaryTiming(htole(timeRegWithDecodeEn
)),
88 deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0),
89 ioEnabled(false), bmEnabled(false)
91 if (params()->disks
.size() > 3)
92 panic("IDE controllers support a maximum of 4 devices attached!\n");
94 // Assign the disks to channels
95 int numDisks
= params()->disks
.size();
97 primary
.master
= params()->disks
[0];
99 primary
.slave
= params()->disks
[1];
101 secondary
.master
= params()->disks
[2];
103 secondary
.slave
= params()->disks
[3];
105 for (int i
= 0; i
< params()->disks
.size(); i
++) {
106 params()->disks
[i
]->setController(this);
108 primary
.select(false);
109 secondary
.select(false);
113 IdeController::isDiskSelected(IdeDisk
*diskPtr
)
115 return (primary
.selected
== diskPtr
|| secondary
.selected
== diskPtr
);
119 IdeController::intrPost()
121 primary
.bmiRegs
.status
.intStatus
= 1;
126 IdeController::setDmaComplete(IdeDisk
*disk
)
129 if (disk
== primary
.master
|| disk
== primary
.slave
) {
131 } else if (disk
== secondary
.master
|| disk
== secondary
.slave
) {
132 channel
= &secondary
;
134 panic("Unable to find disk based on pointer %#x\n", disk
);
137 channel
->bmiRegs
.command
.startStop
= 0;
138 channel
->bmiRegs
.status
.active
= 0;
139 channel
->bmiRegs
.status
.intStatus
= 1;
143 IdeController::readConfig(PacketPtr pkt
)
145 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
146 if (offset
< PCI_DEVICE_SPECIFIC
) {
147 return PciDev::readConfig(pkt
);
152 switch (pkt
->getSize()) {
153 case sizeof(uint8_t):
156 pkt
->set
<uint8_t>(deviceTiming
);
159 pkt
->set
<uint8_t>(udmaControl
);
161 case PrimaryTiming
+ 1:
162 pkt
->set
<uint8_t>(bits(htole(primaryTiming
), 15, 8));
164 case SecondaryTiming
+ 1:
165 pkt
->set
<uint8_t>(bits(htole(secondaryTiming
), 15, 8));
168 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 7, 0));
171 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 15, 8));
174 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
177 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 1 data: %#x\n", offset
,
178 (uint32_t)pkt
->get
<uint8_t>());
180 case sizeof(uint16_t):
183 pkt
->set
<uint16_t>(primaryTiming
);
185 case SecondaryTiming
:
186 pkt
->set
<uint16_t>(secondaryTiming
);
189 pkt
->set
<uint16_t>(udmaTiming
);
192 pkt
->set
<uint16_t>(ideConfig
);
195 panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
198 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 2 data: %#x\n", offset
,
199 (uint32_t)pkt
->get
<uint16_t>());
201 case sizeof(uint32_t):
202 panic("No 32bit reads implemented for this device.");
203 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 4 data: %#x\n", offset
,
204 (uint32_t)pkt
->get
<uint32_t>());
207 panic("invalid access size(?) for PCI configspace!\n");
209 pkt
->makeAtomicResponse();
215 IdeController::writeConfig(PacketPtr pkt
)
217 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
218 if (offset
< PCI_DEVICE_SPECIFIC
) {
219 PciDev::writeConfig(pkt
);
221 switch (pkt
->getSize()) {
222 case sizeof(uint8_t):
225 deviceTiming
= pkt
->get
<uint8_t>();
228 udmaControl
= pkt
->get
<uint8_t>();
231 replaceBits(ideConfig
, 7, 0, pkt
->get
<uint8_t>());
234 replaceBits(ideConfig
, 15, 8, pkt
->get
<uint8_t>());
237 panic("Invalid PCI configuration write "
238 "for size 1 offset: %#x!\n", offset
);
240 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 1 data: %#x\n",
241 offset
, (uint32_t)pkt
->get
<uint8_t>());
243 case sizeof(uint16_t):
246 primaryTiming
= pkt
->get
<uint16_t>();
248 case SecondaryTiming
:
249 secondaryTiming
= pkt
->get
<uint16_t>();
252 udmaTiming
= pkt
->get
<uint16_t>();
255 ideConfig
= pkt
->get
<uint16_t>();
258 panic("Invalid PCI configuration write "
259 "for size 2 offset: %#x!\n",
262 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 2 data: %#x\n",
263 offset
, (uint32_t)pkt
->get
<uint16_t>());
265 case sizeof(uint32_t):
266 panic("Write of unimplemented PCI config. register: %x\n", offset
);
269 panic("invalid access size(?) for PCI configspace!\n");
271 pkt
->makeAtomicResponse();
274 /* Trap command register writes and enable IO/BM as appropriate as well as
277 case PCI0_BASE_ADDR0
:
278 if (BARAddrs
[0] != 0)
279 primary
.cmdAddr
= BARAddrs
[0];
282 case PCI0_BASE_ADDR1
:
283 if (BARAddrs
[1] != 0)
284 primary
.ctrlAddr
= BARAddrs
[1];
287 case PCI0_BASE_ADDR2
:
288 if (BARAddrs
[2] != 0)
289 secondary
.cmdAddr
= BARAddrs
[2];
292 case PCI0_BASE_ADDR3
:
293 if (BARAddrs
[3] != 0)
294 secondary
.ctrlAddr
= BARAddrs
[3];
297 case PCI0_BASE_ADDR4
:
298 if (BARAddrs
[4] != 0)
299 bmiAddr
= BARAddrs
[4];
303 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
304 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
311 IdeController::Channel::accessCommand(Addr offset
,
312 int size
, uint8_t *data
, bool read
)
314 const Addr SelectOffset
= 6;
315 const uint8_t SelectDevBit
= 0x10;
317 if (!read
&& offset
== SelectOffset
)
318 select(*data
& SelectDevBit
);
320 if (selected
== NULL
) {
321 assert(size
== sizeof(uint8_t));
324 selected
->readCommand(offset
, size
, data
);
326 selected
->writeCommand(offset
, size
, data
);
331 IdeController::Channel::accessControl(Addr offset
,
332 int size
, uint8_t *data
, bool read
)
334 if (selected
== NULL
) {
335 assert(size
== sizeof(uint8_t));
338 selected
->readControl(offset
, size
, data
);
340 selected
->writeControl(offset
, size
, data
);
345 IdeController::Channel::accessBMI(Addr offset
,
346 int size
, uint8_t *data
, bool read
)
348 assert(offset
+ size
<= sizeof(BMIRegs
));
350 memcpy(data
, (uint8_t *)&bmiRegs
+ offset
, size
);
355 if (size
!= sizeof(uint8_t))
356 panic("Invalid BMIC write size: %x\n", size
);
358 BMICommandReg oldVal
= bmiRegs
.command
;
359 BMICommandReg newVal
= *data
;
361 // if a DMA transfer is in progress, R/W control cannot change
362 if (oldVal
.startStop
&& oldVal
.rw
!= newVal
.rw
)
363 oldVal
.rw
= newVal
.rw
;
365 if (oldVal
.startStop
!= newVal
.startStop
) {
366 if (selected
== NULL
)
367 panic("DMA start for disk which does not exist\n");
369 if (oldVal
.startStop
) {
370 DPRINTF(IdeCtrl
, "Stopping DMA transfer\n");
371 bmiRegs
.status
.active
= 0;
373 selected
->abortDma();
375 DPRINTF(IdeCtrl
, "Starting DMA transfer\n");
376 bmiRegs
.status
.active
= 1;
378 selected
->startDma(letoh(bmiRegs
.bmidtp
));
382 bmiRegs
.command
= newVal
;
387 if (size
!= sizeof(uint8_t))
388 panic("Invalid BMIS write size: %x\n", size
);
390 BMIStatusReg oldVal
= bmiRegs
.status
;
391 BMIStatusReg newVal
= *data
;
393 // the BMIDEA bit is read only
394 newVal
.active
= oldVal
.active
;
396 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
397 if (oldVal
.intStatus
&& newVal
.intStatus
)
398 newVal
.intStatus
= 0; // clear the interrupt?
400 newVal
.intStatus
= oldVal
.intStatus
;
401 if (oldVal
.dmaError
&& newVal
.dmaError
)
404 newVal
.dmaError
= oldVal
.dmaError
;
406 bmiRegs
.status
= newVal
;
409 case BMIDescTablePtr
:
410 if (size
!= sizeof(uint32_t))
411 panic("Invalid BMIDTP write size: %x\n", size
);
412 bmiRegs
.bmidtp
= htole(*(uint32_t *)data
& ~0x3);
415 if (size
!= sizeof(uint8_t) && size
!= sizeof(uint16_t) &&
416 size
!= sizeof(uint32_t))
417 panic("IDE controller write of invalid write size: %x\n", size
);
418 memcpy((uint8_t *)&bmiRegs
+ offset
, data
, size
);
424 IdeController::dispatchAccess(PacketPtr pkt
, bool read
)
427 if (pkt
->getSize() != 1 && pkt
->getSize() != 2 && pkt
->getSize() !=4)
428 panic("Bad IDE read size: %d\n", pkt
->getSize());
431 pkt
->makeAtomicResponse();
432 DPRINTF(IdeCtrl
, "io not enabled\n");
436 Addr addr
= pkt
->getAddr();
437 int size
= pkt
->getSize();
438 uint8_t *dataPtr
= pkt
->getPtr
<uint8_t>();
440 if (addr
>= primary
.cmdAddr
&&
441 addr
< (primary
.cmdAddr
+ primary
.cmdSize
)) {
442 addr
-= primary
.cmdAddr
;
443 primary
.accessCommand(addr
, size
, dataPtr
, read
);
444 } else if (addr
>= primary
.ctrlAddr
&&
445 addr
< (primary
.ctrlAddr
+ primary
.ctrlSize
)) {
446 addr
-= primary
.ctrlAddr
;
447 primary
.accessControl(addr
, size
, dataPtr
, read
);
448 } else if (addr
>= secondary
.cmdAddr
&&
449 addr
< (secondary
.cmdAddr
+ secondary
.cmdSize
)) {
450 addr
-= secondary
.cmdAddr
;
451 secondary
.accessCommand(addr
, size
, dataPtr
, read
);
452 } else if (addr
>= secondary
.ctrlAddr
&&
453 addr
< (secondary
.ctrlAddr
+ secondary
.ctrlSize
)) {
454 addr
-= secondary
.ctrlAddr
;
455 secondary
.accessControl(addr
, size
, dataPtr
, read
);
456 } else if (addr
>= bmiAddr
&& addr
< (bmiAddr
+ bmiSize
)) {
457 if (!read
&& !bmEnabled
)
460 if (addr
< sizeof(Channel::BMIRegs
)) {
461 primary
.accessBMI(addr
, size
, dataPtr
, read
);
463 addr
-= sizeof(Channel::BMIRegs
);
464 secondary
.accessBMI(addr
, size
, dataPtr
, read
);
467 panic("IDE controller access to invalid address: %#x\n", addr
);
471 if (pkt
->getSize() == 1)
472 data
= pkt
->get
<uint8_t>();
473 else if (pkt
->getSize() == 2)
474 data
= pkt
->get
<uint16_t>();
476 data
= pkt
->get
<uint32_t>();
477 DPRINTF(IdeCtrl
, "%s from offset: %#x size: %#x data: %#x\n",
478 read
? "Read" : "Write", pkt
->getAddr(), pkt
->getSize(), data
);
480 pkt
->makeAtomicResponse();
484 IdeController::read(PacketPtr pkt
)
486 dispatchAccess(pkt
, true);
491 IdeController::write(PacketPtr pkt
)
493 dispatchAccess(pkt
, false);
498 IdeController::serialize(std::ostream
&os
)
500 // Serialize the PciDev base class
501 PciDev::serialize(os
);
503 // Serialize channels
504 primary
.serialize("primary", os
);
505 secondary
.serialize("secondary", os
);
507 // Serialize config registers
508 SERIALIZE_SCALAR(primaryTiming
);
509 SERIALIZE_SCALAR(secondaryTiming
);
510 SERIALIZE_SCALAR(deviceTiming
);
511 SERIALIZE_SCALAR(udmaControl
);
512 SERIALIZE_SCALAR(udmaTiming
);
513 SERIALIZE_SCALAR(ideConfig
);
515 // Serialize internal state
516 SERIALIZE_SCALAR(ioEnabled
);
517 SERIALIZE_SCALAR(bmEnabled
);
518 SERIALIZE_SCALAR(bmiAddr
);
519 SERIALIZE_SCALAR(bmiSize
);
523 IdeController::Channel::serialize(const std::string
&base
, std::ostream
&os
)
525 paramOut(os
, base
+ ".cmdAddr", cmdAddr
);
526 paramOut(os
, base
+ ".cmdSize", cmdSize
);
527 paramOut(os
, base
+ ".ctrlAddr", ctrlAddr
);
528 paramOut(os
, base
+ ".ctrlSize", ctrlSize
);
529 uint8_t command
= bmiRegs
.command
;
530 paramOut(os
, base
+ ".bmiRegs.command", command
);
531 paramOut(os
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
532 uint8_t status
= bmiRegs
.status
;
533 paramOut(os
, base
+ ".bmiRegs.status", status
);
534 paramOut(os
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
535 paramOut(os
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
536 paramOut(os
, base
+ ".selectBit", selectBit
);
540 IdeController::unserialize(Checkpoint
*cp
, const std::string
§ion
)
542 // Unserialize the PciDev base class
543 PciDev::unserialize(cp
, section
);
545 // Unserialize channels
546 primary
.unserialize("primary", cp
, section
);
547 secondary
.unserialize("secondary", cp
, section
);
549 // Unserialize config registers
550 UNSERIALIZE_SCALAR(primaryTiming
);
551 UNSERIALIZE_SCALAR(secondaryTiming
);
552 UNSERIALIZE_SCALAR(deviceTiming
);
553 UNSERIALIZE_SCALAR(udmaControl
);
554 UNSERIALIZE_SCALAR(udmaTiming
);
555 UNSERIALIZE_SCALAR(ideConfig
);
557 // Unserialize internal state
558 UNSERIALIZE_SCALAR(ioEnabled
);
559 UNSERIALIZE_SCALAR(bmEnabled
);
560 UNSERIALIZE_SCALAR(bmiAddr
);
561 UNSERIALIZE_SCALAR(bmiSize
);
565 IdeController::Channel::unserialize(const std::string
&base
, Checkpoint
*cp
,
566 const std::string
§ion
)
568 paramIn(cp
, section
, base
+ ".cmdAddr", cmdAddr
);
569 paramIn(cp
, section
, base
+ ".cmdSize", cmdSize
);
570 paramIn(cp
, section
, base
+ ".ctrlAddr", ctrlAddr
);
571 paramIn(cp
, section
, base
+ ".ctrlSize", ctrlSize
);
573 paramIn(cp
, section
, base
+".bmiRegs.command", command
);
574 bmiRegs
.command
= command
;
575 paramIn(cp
, section
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
577 paramIn(cp
, section
, base
+ ".bmiRegs.status", status
);
578 bmiRegs
.status
= status
;
579 paramIn(cp
, section
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
580 paramIn(cp
, section
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
581 paramIn(cp
, section
, base
+ ".selectBit", selectBit
);
586 IdeControllerParams::create()
588 return new IdeController(this);