ide_ctrl.cc revision 9956
1/* 2 * Copyright (c) 2013 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Copyright (c) 2004-2005 The Regents of The University of Michigan 15 * All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions are 19 * met: redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer; 21 * redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution; 24 * neither the name of the copyright holders nor the names of its 25 * contributors may be used to endorse or promote products derived from 26 * this software without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 * 40 * Authors: Andrew Schultz 41 * Ali Saidi 42 * Miguel Serrano 43 */ 44 45#include <string> 46 47#include "cpu/intr_control.hh" 48#include "debug/IdeCtrl.hh" 49#include "dev/ide_ctrl.hh" 50#include "dev/ide_disk.hh" 51#include "mem/packet.hh" 52#include "mem/packet_access.hh" 53#include "params/IdeController.hh" 54#include "sim/byteswap.hh" 55 56// clang complains about std::set being overloaded with Packet::set if 57// we open up the entire namespace std 58using std::string; 59 60// Bus master IDE registers 61enum BMIRegOffset { 62 BMICommand = 0x0, 63 BMIStatus = 0x2, 64 BMIDescTablePtr = 0x4 65}; 66 67// PCI config space registers 68enum ConfRegOffset { 69 PrimaryTiming = 0x40, 70 SecondaryTiming = 0x42, 71 DeviceTiming = 0x44, 72 UDMAControl = 0x48, 73 UDMATiming = 0x4A, 74 IDEConfig = 0x54 75}; 76 77static const uint16_t timeRegWithDecodeEn = 0x8000; 78 79IdeController::Channel::Channel( 80 string newName, Addr _cmdSize, Addr _ctrlSize) : 81 _name(newName), 82 cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize), 83 master(NULL), slave(NULL), selected(NULL) 84{ 85 memset(&bmiRegs, 0, sizeof(bmiRegs)); 86 bmiRegs.status.dmaCap0 = 1; 87 bmiRegs.status.dmaCap1 = 1; 88} 89 90IdeController::Channel::~Channel() 91{ 92} 93 94IdeController::IdeController(Params *p) 95 : PciDevice(p), primary(name() + ".primary", BARSize[0], BARSize[1]), 96 secondary(name() + ".secondary", BARSize[2], BARSize[3]), 97 bmiAddr(0), bmiSize(BARSize[4]), 98 primaryTiming(htole(timeRegWithDecodeEn)), 99 secondaryTiming(htole(timeRegWithDecodeEn)), 100 deviceTiming(0), udmaControl(0), udmaTiming(0), ideConfig(0), 101 ioEnabled(false), bmEnabled(false), 102 ioShift(p->io_shift), ctrlOffset(p->ctrl_offset) 103{ 104 if (params()->disks.size() > 3) 105 panic("IDE controllers support a maximum of 4 devices attached!\n"); 106 107 // Assign the disks to channels 108 int numDisks = params()->disks.size(); 109 if (numDisks > 0) 110 primary.master = params()->disks[0]; 111 if (numDisks > 1) 112 primary.slave = params()->disks[1]; 113 if (numDisks > 2) 114 secondary.master = params()->disks[2]; 115 if (numDisks > 3) 116 secondary.slave = params()->disks[3]; 117 118 for (int i = 0; i < params()->disks.size(); i++) { 119 params()->disks[i]->setController(this); 120 } 121 primary.select(false); 122 secondary.select(false); 123 124 if ((BARAddrs[0] & ~BAR_IO_MASK) && (!legacyIO[0] || ioShift)) { 125 primary.cmdAddr = BARAddrs[0]; primary.cmdSize = BARSize[0]; 126 primary.ctrlAddr = BARAddrs[1]; primary.ctrlSize = BARSize[1]; 127 } 128 if ((BARAddrs[2] & ~BAR_IO_MASK) && (!legacyIO[2] || ioShift)) { 129 secondary.cmdAddr = BARAddrs[2]; secondary.cmdSize = BARSize[2]; 130 secondary.ctrlAddr = BARAddrs[3]; secondary.ctrlSize = BARSize[3]; 131 } 132 133 ioEnabled = (config.command & htole(PCI_CMD_IOSE)); 134 bmEnabled = (config.command & htole(PCI_CMD_BME)); 135} 136 137bool 138IdeController::isDiskSelected(IdeDisk *diskPtr) 139{ 140 return (primary.selected == diskPtr || secondary.selected == diskPtr); 141} 142 143void 144IdeController::intrPost() 145{ 146 primary.bmiRegs.status.intStatus = 1; 147 PciDevice::intrPost(); 148} 149 150void 151IdeController::setDmaComplete(IdeDisk *disk) 152{ 153 Channel *channel; 154 if (disk == primary.master || disk == primary.slave) { 155 channel = &primary; 156 } else if (disk == secondary.master || disk == secondary.slave) { 157 channel = &secondary; 158 } else { 159 panic("Unable to find disk based on pointer %#x\n", disk); 160 } 161 162 channel->bmiRegs.command.startStop = 0; 163 channel->bmiRegs.status.active = 0; 164 channel->bmiRegs.status.intStatus = 1; 165} 166 167Tick 168IdeController::readConfig(PacketPtr pkt) 169{ 170 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 171 if (offset < PCI_DEVICE_SPECIFIC) { 172 return PciDevice::readConfig(pkt); 173 } 174 175 pkt->allocate(); 176 177 switch (pkt->getSize()) { 178 case sizeof(uint8_t): 179 switch (offset) { 180 case DeviceTiming: 181 pkt->set<uint8_t>(deviceTiming); 182 break; 183 case UDMAControl: 184 pkt->set<uint8_t>(udmaControl); 185 break; 186 case PrimaryTiming + 1: 187 pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8)); 188 break; 189 case SecondaryTiming + 1: 190 pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8)); 191 break; 192 case IDEConfig: 193 pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0)); 194 break; 195 case IDEConfig + 1: 196 pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8)); 197 break; 198 default: 199 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n", 200 offset); 201 } 202 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset, 203 (uint32_t)pkt->get<uint8_t>()); 204 break; 205 case sizeof(uint16_t): 206 switch (offset) { 207 case PrimaryTiming: 208 pkt->set<uint16_t>(primaryTiming); 209 break; 210 case SecondaryTiming: 211 pkt->set<uint16_t>(secondaryTiming); 212 break; 213 case UDMATiming: 214 pkt->set<uint16_t>(udmaTiming); 215 break; 216 case IDEConfig: 217 pkt->set<uint16_t>(ideConfig); 218 break; 219 default: 220 panic("Invalid PCI configuration read for size 2 offset: %#x!\n", 221 offset); 222 } 223 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset, 224 (uint32_t)pkt->get<uint16_t>()); 225 break; 226 case sizeof(uint32_t): 227 if (offset == IDEConfig) 228 pkt->set<uint32_t>(ideConfig); 229 else 230 panic("No 32bit reads implemented for this device."); 231 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset, 232 (uint32_t)pkt->get<uint32_t>()); 233 break; 234 default: 235 panic("invalid access size(?) for PCI configspace!\n"); 236 } 237 pkt->makeAtomicResponse(); 238 return configDelay; 239} 240 241 242Tick 243IdeController::writeConfig(PacketPtr pkt) 244{ 245 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 246 if (offset < PCI_DEVICE_SPECIFIC) { 247 PciDevice::writeConfig(pkt); 248 } else { 249 switch (pkt->getSize()) { 250 case sizeof(uint8_t): 251 switch (offset) { 252 case DeviceTiming: 253 deviceTiming = pkt->get<uint8_t>(); 254 break; 255 case UDMAControl: 256 udmaControl = pkt->get<uint8_t>(); 257 break; 258 case IDEConfig: 259 replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>()); 260 break; 261 case IDEConfig + 1: 262 replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>()); 263 break; 264 default: 265 panic("Invalid PCI configuration write " 266 "for size 1 offset: %#x!\n", offset); 267 } 268 DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n", 269 offset, (uint32_t)pkt->get<uint8_t>()); 270 break; 271 case sizeof(uint16_t): 272 switch (offset) { 273 case PrimaryTiming: 274 primaryTiming = pkt->get<uint16_t>(); 275 break; 276 case SecondaryTiming: 277 secondaryTiming = pkt->get<uint16_t>(); 278 break; 279 case UDMATiming: 280 udmaTiming = pkt->get<uint16_t>(); 281 break; 282 case IDEConfig: 283 ideConfig = pkt->get<uint16_t>(); 284 break; 285 default: 286 panic("Invalid PCI configuration write " 287 "for size 2 offset: %#x!\n", 288 offset); 289 } 290 DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", 291 offset, (uint32_t)pkt->get<uint16_t>()); 292 break; 293 case sizeof(uint32_t): 294 if (offset == IDEConfig) 295 ideConfig = pkt->get<uint32_t>(); 296 else 297 panic("Write of unimplemented PCI config. register: %x\n", offset); 298 break; 299 default: 300 panic("invalid access size(?) for PCI configspace!\n"); 301 } 302 pkt->makeAtomicResponse(); 303 } 304 305 /* Trap command register writes and enable IO/BM as appropriate as well as 306 * BARs. */ 307 switch(offset) { 308 case PCI0_BASE_ADDR0: 309 if (BARAddrs[0] != 0) 310 primary.cmdAddr = BARAddrs[0]; 311 break; 312 313 case PCI0_BASE_ADDR1: 314 if (BARAddrs[1] != 0) 315 primary.ctrlAddr = BARAddrs[1]; 316 break; 317 318 case PCI0_BASE_ADDR2: 319 if (BARAddrs[2] != 0) 320 secondary.cmdAddr = BARAddrs[2]; 321 break; 322 323 case PCI0_BASE_ADDR3: 324 if (BARAddrs[3] != 0) 325 secondary.ctrlAddr = BARAddrs[3]; 326 break; 327 328 case PCI0_BASE_ADDR4: 329 if (BARAddrs[4] != 0) 330 bmiAddr = BARAddrs[4]; 331 break; 332 333 case PCI_COMMAND: 334 DPRINTF(IdeCtrl, "Writing to PCI Command val: %#x\n", config.command); 335 ioEnabled = (config.command & htole(PCI_CMD_IOSE)); 336 bmEnabled = (config.command & htole(PCI_CMD_BME)); 337 break; 338 } 339 return configDelay; 340} 341 342void 343IdeController::Channel::accessCommand(Addr offset, 344 int size, uint8_t *data, bool read) 345{ 346 const Addr SelectOffset = 6; 347 const uint8_t SelectDevBit = 0x10; 348 349 if (!read && offset == SelectOffset) 350 select(*data & SelectDevBit); 351 352 if (selected == NULL) { 353 assert(size == sizeof(uint8_t)); 354 *data = 0; 355 } else if (read) { 356 selected->readCommand(offset, size, data); 357 } else { 358 selected->writeCommand(offset, size, data); 359 } 360} 361 362void 363IdeController::Channel::accessControl(Addr offset, 364 int size, uint8_t *data, bool read) 365{ 366 if (selected == NULL) { 367 assert(size == sizeof(uint8_t)); 368 *data = 0; 369 } else if (read) { 370 selected->readControl(offset, size, data); 371 } else { 372 selected->writeControl(offset, size, data); 373 } 374} 375 376void 377IdeController::Channel::accessBMI(Addr offset, 378 int size, uint8_t *data, bool read) 379{ 380 assert(offset + size <= sizeof(BMIRegs)); 381 if (read) { 382 memcpy(data, (uint8_t *)&bmiRegs + offset, size); 383 } else { 384 switch (offset) { 385 case BMICommand: 386 { 387 if (size != sizeof(uint8_t)) 388 panic("Invalid BMIC write size: %x\n", size); 389 390 BMICommandReg oldVal = bmiRegs.command; 391 BMICommandReg newVal = *data; 392 393 // if a DMA transfer is in progress, R/W control cannot change 394 if (oldVal.startStop && oldVal.rw != newVal.rw) 395 oldVal.rw = newVal.rw; 396 397 if (oldVal.startStop != newVal.startStop) { 398 if (selected == NULL) 399 panic("DMA start for disk which does not exist\n"); 400 401 if (oldVal.startStop) { 402 DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); 403 bmiRegs.status.active = 0; 404 405 selected->abortDma(); 406 } else { 407 DPRINTF(IdeCtrl, "Starting DMA transfer\n"); 408 bmiRegs.status.active = 1; 409 410 selected->startDma(letoh(bmiRegs.bmidtp)); 411 } 412 } 413 414 bmiRegs.command = newVal; 415 } 416 break; 417 case BMIStatus: 418 { 419 if (size != sizeof(uint8_t)) 420 panic("Invalid BMIS write size: %x\n", size); 421 422 BMIStatusReg oldVal = bmiRegs.status; 423 BMIStatusReg newVal = *data; 424 425 // the BMIDEA bit is read only 426 newVal.active = oldVal.active; 427 428 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each 429 if ((oldVal.intStatus == 1) && (newVal.intStatus == 1)) { 430 newVal.intStatus = 0; // clear the interrupt? 431 } else { 432 // Assigning two bitunion fields to each other does not 433 // work as intended, so we need to use this temporary variable 434 // to get around the bug. 435 uint8_t tmp = oldVal.intStatus; 436 newVal.intStatus = tmp; 437 } 438 if ((oldVal.dmaError == 1) && (newVal.dmaError == 1)) { 439 newVal.dmaError = 0; 440 } else { 441 uint8_t tmp = oldVal.dmaError; 442 newVal.dmaError = tmp; 443 } 444 445 bmiRegs.status = newVal; 446 } 447 break; 448 case BMIDescTablePtr: 449 if (size != sizeof(uint32_t)) 450 panic("Invalid BMIDTP write size: %x\n", size); 451 bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3); 452 break; 453 default: 454 if (size != sizeof(uint8_t) && size != sizeof(uint16_t) && 455 size != sizeof(uint32_t)) 456 panic("IDE controller write of invalid write size: %x\n", size); 457 memcpy((uint8_t *)&bmiRegs + offset, data, size); 458 } 459 } 460} 461 462void 463IdeController::dispatchAccess(PacketPtr pkt, bool read) 464{ 465 pkt->allocate(); 466 if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4) 467 panic("Bad IDE read size: %d\n", pkt->getSize()); 468 469 if (!ioEnabled) { 470 pkt->makeAtomicResponse(); 471 DPRINTF(IdeCtrl, "io not enabled\n"); 472 return; 473 } 474 475 Addr addr = pkt->getAddr(); 476 int size = pkt->getSize(); 477 uint8_t *dataPtr = pkt->getPtr<uint8_t>(); 478 479 if (addr >= primary.cmdAddr && 480 addr < (primary.cmdAddr + primary.cmdSize)) { 481 addr -= primary.cmdAddr; 482 // linux may have shifted the address by ioShift, 483 // here we shift it back, similarly for ctrlOffset. 484 addr >>= ioShift; 485 primary.accessCommand(addr, size, dataPtr, read); 486 } else if (addr >= primary.ctrlAddr && 487 addr < (primary.ctrlAddr + primary.ctrlSize)) { 488 addr -= primary.ctrlAddr; 489 addr += ctrlOffset; 490 primary.accessControl(addr, size, dataPtr, read); 491 } else if (addr >= secondary.cmdAddr && 492 addr < (secondary.cmdAddr + secondary.cmdSize)) { 493 addr -= secondary.cmdAddr; 494 secondary.accessCommand(addr, size, dataPtr, read); 495 } else if (addr >= secondary.ctrlAddr && 496 addr < (secondary.ctrlAddr + secondary.ctrlSize)) { 497 addr -= secondary.ctrlAddr; 498 secondary.accessControl(addr, size, dataPtr, read); 499 } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) { 500 if (!read && !bmEnabled) 501 return; 502 addr -= bmiAddr; 503 if (addr < sizeof(Channel::BMIRegs)) { 504 primary.accessBMI(addr, size, dataPtr, read); 505 } else { 506 addr -= sizeof(Channel::BMIRegs); 507 secondary.accessBMI(addr, size, dataPtr, read); 508 } 509 } else { 510 panic("IDE controller access to invalid address: %#x\n", addr); 511 } 512 513#ifndef NDEBUG 514 uint32_t data; 515 if (pkt->getSize() == 1) 516 data = pkt->get<uint8_t>(); 517 else if (pkt->getSize() == 2) 518 data = pkt->get<uint16_t>(); 519 else 520 data = pkt->get<uint32_t>(); 521 DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n", 522 read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data); 523#endif 524 525 pkt->makeAtomicResponse(); 526} 527 528Tick 529IdeController::read(PacketPtr pkt) 530{ 531 dispatchAccess(pkt, true); 532 return pioDelay; 533} 534 535Tick 536IdeController::write(PacketPtr pkt) 537{ 538 dispatchAccess(pkt, false); 539 return pioDelay; 540} 541 542void 543IdeController::serialize(std::ostream &os) 544{ 545 // Serialize the PciDevice base class 546 PciDevice::serialize(os); 547 548 // Serialize channels 549 primary.serialize("primary", os); 550 secondary.serialize("secondary", os); 551 552 // Serialize config registers 553 SERIALIZE_SCALAR(primaryTiming); 554 SERIALIZE_SCALAR(secondaryTiming); 555 SERIALIZE_SCALAR(deviceTiming); 556 SERIALIZE_SCALAR(udmaControl); 557 SERIALIZE_SCALAR(udmaTiming); 558 SERIALIZE_SCALAR(ideConfig); 559 560 // Serialize internal state 561 SERIALIZE_SCALAR(ioEnabled); 562 SERIALIZE_SCALAR(bmEnabled); 563 SERIALIZE_SCALAR(bmiAddr); 564 SERIALIZE_SCALAR(bmiSize); 565} 566 567void 568IdeController::Channel::serialize(const std::string &base, std::ostream &os) 569{ 570 paramOut(os, base + ".cmdAddr", cmdAddr); 571 paramOut(os, base + ".cmdSize", cmdSize); 572 paramOut(os, base + ".ctrlAddr", ctrlAddr); 573 paramOut(os, base + ".ctrlSize", ctrlSize); 574 uint8_t command = bmiRegs.command; 575 paramOut(os, base + ".bmiRegs.command", command); 576 paramOut(os, base + ".bmiRegs.reserved0", bmiRegs.reserved0); 577 uint8_t status = bmiRegs.status; 578 paramOut(os, base + ".bmiRegs.status", status); 579 paramOut(os, base + ".bmiRegs.reserved1", bmiRegs.reserved1); 580 paramOut(os, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp); 581 paramOut(os, base + ".selectBit", selectBit); 582} 583 584void 585IdeController::unserialize(Checkpoint *cp, const std::string §ion) 586{ 587 // Unserialize the PciDevice base class 588 PciDevice::unserialize(cp, section); 589 590 // Unserialize channels 591 primary.unserialize("primary", cp, section); 592 secondary.unserialize("secondary", cp, section); 593 594 // Unserialize config registers 595 UNSERIALIZE_SCALAR(primaryTiming); 596 UNSERIALIZE_SCALAR(secondaryTiming); 597 UNSERIALIZE_SCALAR(deviceTiming); 598 UNSERIALIZE_SCALAR(udmaControl); 599 UNSERIALIZE_SCALAR(udmaTiming); 600 UNSERIALIZE_SCALAR(ideConfig); 601 602 // Unserialize internal state 603 UNSERIALIZE_SCALAR(ioEnabled); 604 UNSERIALIZE_SCALAR(bmEnabled); 605 UNSERIALIZE_SCALAR(bmiAddr); 606 UNSERIALIZE_SCALAR(bmiSize); 607} 608 609void 610IdeController::Channel::unserialize(const std::string &base, Checkpoint *cp, 611 const std::string §ion) 612{ 613 paramIn(cp, section, base + ".cmdAddr", cmdAddr); 614 paramIn(cp, section, base + ".cmdSize", cmdSize); 615 paramIn(cp, section, base + ".ctrlAddr", ctrlAddr); 616 paramIn(cp, section, base + ".ctrlSize", ctrlSize); 617 uint8_t command; 618 paramIn(cp, section, base +".bmiRegs.command", command); 619 bmiRegs.command = command; 620 paramIn(cp, section, base + ".bmiRegs.reserved0", bmiRegs.reserved0); 621 uint8_t status; 622 paramIn(cp, section, base + ".bmiRegs.status", status); 623 bmiRegs.status = status; 624 paramIn(cp, section, base + ".bmiRegs.reserved1", bmiRegs.reserved1); 625 paramIn(cp, section, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp); 626 paramIn(cp, section, base + ".selectBit", selectBit); 627 select(selectBit); 628} 629 630IdeController * 631IdeControllerParams::create() 632{ 633 return new IdeController(this); 634} 635