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);
111 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
112 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
116 IdeController::isDiskSelected(IdeDisk
*diskPtr
)
118 return (primary
.selected
== diskPtr
|| secondary
.selected
== diskPtr
);
122 IdeController::intrPost()
124 primary
.bmiRegs
.status
.intStatus
= 1;
129 IdeController::setDmaComplete(IdeDisk
*disk
)
132 if (disk
== primary
.master
|| disk
== primary
.slave
) {
134 } else if (disk
== secondary
.master
|| disk
== secondary
.slave
) {
135 channel
= &secondary
;
137 panic("Unable to find disk based on pointer %#x\n", disk
);
140 channel
->bmiRegs
.command
.startStop
= 0;
141 channel
->bmiRegs
.status
.active
= 0;
142 channel
->bmiRegs
.status
.intStatus
= 1;
146 IdeController::readConfig(PacketPtr pkt
)
148 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
149 if (offset
< PCI_DEVICE_SPECIFIC
) {
150 return PciDev::readConfig(pkt
);
155 switch (pkt
->getSize()) {
156 case sizeof(uint8_t):
159 pkt
->set
<uint8_t>(deviceTiming
);
162 pkt
->set
<uint8_t>(udmaControl
);
164 case PrimaryTiming
+ 1:
165 pkt
->set
<uint8_t>(bits(htole(primaryTiming
), 15, 8));
167 case SecondaryTiming
+ 1:
168 pkt
->set
<uint8_t>(bits(htole(secondaryTiming
), 15, 8));
171 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 7, 0));
174 pkt
->set
<uint8_t>(bits(htole(ideConfig
), 15, 8));
177 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
180 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 1 data: %#x\n", offset
,
181 (uint32_t)pkt
->get
<uint8_t>());
183 case sizeof(uint16_t):
186 pkt
->set
<uint16_t>(primaryTiming
);
188 case SecondaryTiming
:
189 pkt
->set
<uint16_t>(secondaryTiming
);
192 pkt
->set
<uint16_t>(udmaTiming
);
195 pkt
->set
<uint16_t>(ideConfig
);
198 panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
201 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 2 data: %#x\n", offset
,
202 (uint32_t)pkt
->get
<uint16_t>());
204 case sizeof(uint32_t):
205 panic("No 32bit reads implemented for this device.");
206 DPRINTF(IdeCtrl
, "PCI read offset: %#x size: 4 data: %#x\n", offset
,
207 (uint32_t)pkt
->get
<uint32_t>());
210 panic("invalid access size(?) for PCI configspace!\n");
212 pkt
->makeAtomicResponse();
218 IdeController::writeConfig(PacketPtr pkt
)
220 int offset
= pkt
->getAddr() & PCI_CONFIG_SIZE
;
221 if (offset
< PCI_DEVICE_SPECIFIC
) {
222 PciDev::writeConfig(pkt
);
224 switch (pkt
->getSize()) {
225 case sizeof(uint8_t):
228 deviceTiming
= pkt
->get
<uint8_t>();
231 udmaControl
= pkt
->get
<uint8_t>();
234 replaceBits(ideConfig
, 7, 0, pkt
->get
<uint8_t>());
237 replaceBits(ideConfig
, 15, 8, pkt
->get
<uint8_t>());
240 panic("Invalid PCI configuration write "
241 "for size 1 offset: %#x!\n", offset
);
243 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 1 data: %#x\n",
244 offset
, (uint32_t)pkt
->get
<uint8_t>());
246 case sizeof(uint16_t):
249 primaryTiming
= pkt
->get
<uint16_t>();
251 case SecondaryTiming
:
252 secondaryTiming
= pkt
->get
<uint16_t>();
255 udmaTiming
= pkt
->get
<uint16_t>();
258 ideConfig
= pkt
->get
<uint16_t>();
261 panic("Invalid PCI configuration write "
262 "for size 2 offset: %#x!\n",
265 DPRINTF(IdeCtrl
, "PCI write offset: %#x size: 2 data: %#x\n",
266 offset
, (uint32_t)pkt
->get
<uint16_t>());
268 case sizeof(uint32_t):
269 panic("Write of unimplemented PCI config. register: %x\n", offset
);
272 panic("invalid access size(?) for PCI configspace!\n");
274 pkt
->makeAtomicResponse();
277 /* Trap command register writes and enable IO/BM as appropriate as well as
280 case PCI0_BASE_ADDR0
:
281 if (BARAddrs
[0] != 0)
282 primary
.cmdAddr
= BARAddrs
[0];
285 case PCI0_BASE_ADDR1
:
286 if (BARAddrs
[1] != 0)
287 primary
.ctrlAddr
= BARAddrs
[1];
290 case PCI0_BASE_ADDR2
:
291 if (BARAddrs
[2] != 0)
292 secondary
.cmdAddr
= BARAddrs
[2];
295 case PCI0_BASE_ADDR3
:
296 if (BARAddrs
[3] != 0)
297 secondary
.ctrlAddr
= BARAddrs
[3];
300 case PCI0_BASE_ADDR4
:
301 if (BARAddrs
[4] != 0)
302 bmiAddr
= BARAddrs
[4];
306 ioEnabled
= (config
.command
& htole(PCI_CMD_IOSE
));
307 bmEnabled
= (config
.command
& htole(PCI_CMD_BME
));
314 IdeController::Channel::accessCommand(Addr offset
,
315 int size
, uint8_t *data
, bool read
)
317 const Addr SelectOffset
= 6;
318 const uint8_t SelectDevBit
= 0x10;
320 if (!read
&& offset
== SelectOffset
)
321 select(*data
& SelectDevBit
);
323 if (selected
== NULL
) {
324 assert(size
== sizeof(uint8_t));
327 selected
->readCommand(offset
, size
, data
);
329 selected
->writeCommand(offset
, size
, data
);
334 IdeController::Channel::accessControl(Addr offset
,
335 int size
, uint8_t *data
, bool read
)
337 if (selected
== NULL
) {
338 assert(size
== sizeof(uint8_t));
341 selected
->readControl(offset
, size
, data
);
343 selected
->writeControl(offset
, size
, data
);
348 IdeController::Channel::accessBMI(Addr offset
,
349 int size
, uint8_t *data
, bool read
)
351 assert(offset
+ size
<= sizeof(BMIRegs
));
353 memcpy(data
, (uint8_t *)&bmiRegs
+ offset
, size
);
358 if (size
!= sizeof(uint8_t))
359 panic("Invalid BMIC write size: %x\n", size
);
361 BMICommandReg oldVal
= bmiRegs
.command
;
362 BMICommandReg newVal
= *data
;
364 // if a DMA transfer is in progress, R/W control cannot change
365 if (oldVal
.startStop
&& oldVal
.rw
!= newVal
.rw
)
366 oldVal
.rw
= newVal
.rw
;
368 if (oldVal
.startStop
!= newVal
.startStop
) {
369 if (selected
== NULL
)
370 panic("DMA start for disk which does not exist\n");
372 if (oldVal
.startStop
) {
373 DPRINTF(IdeCtrl
, "Stopping DMA transfer\n");
374 bmiRegs
.status
.active
= 0;
376 selected
->abortDma();
378 DPRINTF(IdeCtrl
, "Starting DMA transfer\n");
379 bmiRegs
.status
.active
= 1;
381 selected
->startDma(letoh(bmiRegs
.bmidtp
));
385 bmiRegs
.command
= newVal
;
390 if (size
!= sizeof(uint8_t))
391 panic("Invalid BMIS write size: %x\n", size
);
393 BMIStatusReg oldVal
= bmiRegs
.status
;
394 BMIStatusReg newVal
= *data
;
396 // the BMIDEA bit is read only
397 newVal
.active
= oldVal
.active
;
399 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
400 if (oldVal
.intStatus
&& newVal
.intStatus
)
401 newVal
.intStatus
= 0; // clear the interrupt?
403 newVal
.intStatus
= oldVal
.intStatus
;
404 if (oldVal
.dmaError
&& newVal
.dmaError
)
407 newVal
.dmaError
= oldVal
.dmaError
;
409 bmiRegs
.status
= newVal
;
412 case BMIDescTablePtr
:
413 if (size
!= sizeof(uint32_t))
414 panic("Invalid BMIDTP write size: %x\n", size
);
415 bmiRegs
.bmidtp
= htole(*(uint32_t *)data
& ~0x3);
418 if (size
!= sizeof(uint8_t) && size
!= sizeof(uint16_t) &&
419 size
!= sizeof(uint32_t))
420 panic("IDE controller write of invalid write size: %x\n", size
);
421 memcpy((uint8_t *)&bmiRegs
+ offset
, data
, size
);
427 IdeController::dispatchAccess(PacketPtr pkt
, bool read
)
430 if (pkt
->getSize() != 1 && pkt
->getSize() != 2 && pkt
->getSize() !=4)
431 panic("Bad IDE read size: %d\n", pkt
->getSize());
434 pkt
->makeAtomicResponse();
435 DPRINTF(IdeCtrl
, "io not enabled\n");
439 Addr addr
= pkt
->getAddr();
440 int size
= pkt
->getSize();
441 uint8_t *dataPtr
= pkt
->getPtr
<uint8_t>();
443 if (addr
>= primary
.cmdAddr
&&
444 addr
< (primary
.cmdAddr
+ primary
.cmdSize
)) {
445 addr
-= primary
.cmdAddr
;
446 primary
.accessCommand(addr
, size
, dataPtr
, read
);
447 } else if (addr
>= primary
.ctrlAddr
&&
448 addr
< (primary
.ctrlAddr
+ primary
.ctrlSize
)) {
449 addr
-= primary
.ctrlAddr
;
450 primary
.accessControl(addr
, size
, dataPtr
, read
);
451 } else if (addr
>= secondary
.cmdAddr
&&
452 addr
< (secondary
.cmdAddr
+ secondary
.cmdSize
)) {
453 addr
-= secondary
.cmdAddr
;
454 secondary
.accessCommand(addr
, size
, dataPtr
, read
);
455 } else if (addr
>= secondary
.ctrlAddr
&&
456 addr
< (secondary
.ctrlAddr
+ secondary
.ctrlSize
)) {
457 addr
-= secondary
.ctrlAddr
;
458 secondary
.accessControl(addr
, size
, dataPtr
, read
);
459 } else if (addr
>= bmiAddr
&& addr
< (bmiAddr
+ bmiSize
)) {
460 if (!read
&& !bmEnabled
)
463 if (addr
< sizeof(Channel::BMIRegs
)) {
464 primary
.accessBMI(addr
, size
, dataPtr
, read
);
466 addr
-= sizeof(Channel::BMIRegs
);
467 secondary
.accessBMI(addr
, size
, dataPtr
, read
);
470 panic("IDE controller access to invalid address: %#x\n", addr
);
474 if (pkt
->getSize() == 1)
475 data
= pkt
->get
<uint8_t>();
476 else if (pkt
->getSize() == 2)
477 data
= pkt
->get
<uint16_t>();
479 data
= pkt
->get
<uint32_t>();
480 DPRINTF(IdeCtrl
, "%s from offset: %#x size: %#x data: %#x\n",
481 read
? "Read" : "Write", pkt
->getAddr(), pkt
->getSize(), data
);
483 pkt
->makeAtomicResponse();
487 IdeController::read(PacketPtr pkt
)
489 dispatchAccess(pkt
, true);
494 IdeController::write(PacketPtr pkt
)
496 dispatchAccess(pkt
, false);
501 IdeController::serialize(std::ostream
&os
)
503 // Serialize the PciDev base class
504 PciDev::serialize(os
);
506 // Serialize channels
507 primary
.serialize("primary", os
);
508 secondary
.serialize("secondary", os
);
510 // Serialize config registers
511 SERIALIZE_SCALAR(primaryTiming
);
512 SERIALIZE_SCALAR(secondaryTiming
);
513 SERIALIZE_SCALAR(deviceTiming
);
514 SERIALIZE_SCALAR(udmaControl
);
515 SERIALIZE_SCALAR(udmaTiming
);
516 SERIALIZE_SCALAR(ideConfig
);
518 // Serialize internal state
519 SERIALIZE_SCALAR(ioEnabled
);
520 SERIALIZE_SCALAR(bmEnabled
);
521 SERIALIZE_SCALAR(bmiAddr
);
522 SERIALIZE_SCALAR(bmiSize
);
526 IdeController::Channel::serialize(const std::string
&base
, std::ostream
&os
)
528 paramOut(os
, base
+ ".cmdAddr", cmdAddr
);
529 paramOut(os
, base
+ ".cmdSize", cmdSize
);
530 paramOut(os
, base
+ ".ctrlAddr", ctrlAddr
);
531 paramOut(os
, base
+ ".ctrlSize", ctrlSize
);
532 uint8_t command
= bmiRegs
.command
;
533 paramOut(os
, base
+ ".bmiRegs.command", command
);
534 paramOut(os
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
535 uint8_t status
= bmiRegs
.status
;
536 paramOut(os
, base
+ ".bmiRegs.status", status
);
537 paramOut(os
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
538 paramOut(os
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
539 paramOut(os
, base
+ ".selectBit", selectBit
);
543 IdeController::unserialize(Checkpoint
*cp
, const std::string
§ion
)
545 // Unserialize the PciDev base class
546 PciDev::unserialize(cp
, section
);
548 // Unserialize channels
549 primary
.unserialize("primary", cp
, section
);
550 secondary
.unserialize("secondary", cp
, section
);
552 // Unserialize config registers
553 UNSERIALIZE_SCALAR(primaryTiming
);
554 UNSERIALIZE_SCALAR(secondaryTiming
);
555 UNSERIALIZE_SCALAR(deviceTiming
);
556 UNSERIALIZE_SCALAR(udmaControl
);
557 UNSERIALIZE_SCALAR(udmaTiming
);
558 UNSERIALIZE_SCALAR(ideConfig
);
560 // Unserialize internal state
561 UNSERIALIZE_SCALAR(ioEnabled
);
562 UNSERIALIZE_SCALAR(bmEnabled
);
563 UNSERIALIZE_SCALAR(bmiAddr
);
564 UNSERIALIZE_SCALAR(bmiSize
);
568 IdeController::Channel::unserialize(const std::string
&base
, Checkpoint
*cp
,
569 const std::string
§ion
)
571 paramIn(cp
, section
, base
+ ".cmdAddr", cmdAddr
);
572 paramIn(cp
, section
, base
+ ".cmdSize", cmdSize
);
573 paramIn(cp
, section
, base
+ ".ctrlAddr", ctrlAddr
);
574 paramIn(cp
, section
, base
+ ".ctrlSize", ctrlSize
);
576 paramIn(cp
, section
, base
+".bmiRegs.command", command
);
577 bmiRegs
.command
= command
;
578 paramIn(cp
, section
, base
+ ".bmiRegs.reserved0", bmiRegs
.reserved0
);
580 paramIn(cp
, section
, base
+ ".bmiRegs.status", status
);
581 bmiRegs
.status
= status
;
582 paramIn(cp
, section
, base
+ ".bmiRegs.reserved1", bmiRegs
.reserved1
);
583 paramIn(cp
, section
, base
+ ".bmiRegs.bmidtp", bmiRegs
.bmidtp
);
584 paramIn(cp
, section
, base
+ ".selectBit", selectBit
);
589 IdeControllerParams::create()
591 return new IdeController(this);