ide_ctrl.cc revision 5772
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 <string> 34 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" 43 44using namespace std; 45 46// Bus master IDE registers 47enum BMIRegOffset { 48 BMICommand = 0x0, 49 BMIStatus = 0x2, 50 BMIDescTablePtr = 0x4 51}; 52 53// PCI config space registers 54enum ConfRegOffset { 55 PrimaryTiming = 0x40, 56 SecondaryTiming = 0x42, 57 DeviceTiming = 0x44, 58 UDMAControl = 0x48, 59 UDMATiming = 0x4A, 60 IDEConfig = 0x54 61}; 62 63static const uint16_t timeRegWithDecodeEn = 0x8000; 64 65IdeController::Channel::Channel( 66 string newName, Addr _cmdSize, Addr _ctrlSize) : 67 _name(newName), 68 cmdAddr(0), cmdSize(_cmdSize), ctrlAddr(0), ctrlSize(_ctrlSize), 69 master(NULL), slave(NULL), selected(NULL) 70{ 71 memset(&bmiRegs, 0, sizeof(bmiRegs)); 72 bmiRegs.status.dmaCap0 = 1; 73 bmiRegs.status.dmaCap1 = 1; 74} 75 76IdeController::Channel::~Channel() 77{ 78 delete master; 79 delete slave; 80} 81 82IdeController::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) 90{ 91 if (params()->disks.size() > 3) 92 panic("IDE controllers support a maximum of 4 devices attached!\n"); 93 94 // Assign the disks to channels 95 int numDisks = params()->disks.size(); 96 if (numDisks > 0) 97 primary.master = params()->disks[0]; 98 if (numDisks > 1) 99 primary.slave = params()->disks[1]; 100 if (numDisks > 2) 101 secondary.master = params()->disks[2]; 102 if (numDisks > 3) 103 secondary.slave = params()->disks[3]; 104 105 for (int i = 0; i < params()->disks.size(); i++) { 106 params()->disks[i]->setController(this); 107 } 108 primary.select(false); 109 secondary.select(false); 110} 111 112bool 113IdeController::isDiskSelected(IdeDisk *diskPtr) 114{ 115 return (primary.selected == diskPtr || secondary.selected == diskPtr); 116} 117 118void 119IdeController::intrPost() 120{ 121 primary.bmiRegs.status.intStatus = 1; 122 PciDev::intrPost(); 123} 124 125void 126IdeController::setDmaComplete(IdeDisk *disk) 127{ 128 Channel *channel; 129 if (disk == primary.master || disk == primary.slave) { 130 channel = &primary; 131 } else if (disk == secondary.master || disk == secondary.slave) { 132 channel = &secondary; 133 } else { 134 panic("Unable to find disk based on pointer %#x\n", disk); 135 } 136 137 channel->bmiRegs.command.startStop = 0; 138 channel->bmiRegs.status.active = 0; 139 channel->bmiRegs.status.intStatus = 1; 140} 141 142Tick 143IdeController::readConfig(PacketPtr pkt) 144{ 145 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 146 if (offset < PCI_DEVICE_SPECIFIC) { 147 return PciDev::readConfig(pkt); 148 } 149 150 pkt->allocate(); 151 152 switch (pkt->getSize()) { 153 case sizeof(uint8_t): 154 switch (offset) { 155 case DeviceTiming: 156 pkt->set<uint8_t>(deviceTiming); 157 break; 158 case UDMAControl: 159 pkt->set<uint8_t>(udmaControl); 160 break; 161 case PrimaryTiming + 1: 162 pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8)); 163 break; 164 case SecondaryTiming + 1: 165 pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8)); 166 break; 167 case IDEConfig: 168 pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0)); 169 break; 170 case IDEConfig + 1: 171 pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8)); 172 break; 173 default: 174 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n", 175 offset); 176 } 177 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset, 178 (uint32_t)pkt->get<uint8_t>()); 179 break; 180 case sizeof(uint16_t): 181 switch (offset) { 182 case PrimaryTiming: 183 pkt->set<uint16_t>(primaryTiming); 184 break; 185 case SecondaryTiming: 186 pkt->set<uint16_t>(secondaryTiming); 187 break; 188 case UDMATiming: 189 pkt->set<uint16_t>(udmaTiming); 190 break; 191 case IDEConfig: 192 pkt->set<uint16_t>(ideConfig); 193 break; 194 default: 195 panic("Invalid PCI configuration read for size 2 offset: %#x!\n", 196 offset); 197 } 198 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset, 199 (uint32_t)pkt->get<uint16_t>()); 200 break; 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>()); 205 break; 206 default: 207 panic("invalid access size(?) for PCI configspace!\n"); 208 } 209 pkt->makeAtomicResponse(); 210 return configDelay; 211} 212 213 214Tick 215IdeController::writeConfig(PacketPtr pkt) 216{ 217 int offset = pkt->getAddr() & PCI_CONFIG_SIZE; 218 if (offset < PCI_DEVICE_SPECIFIC) { 219 PciDev::writeConfig(pkt); 220 } else { 221 switch (pkt->getSize()) { 222 case sizeof(uint8_t): 223 switch (offset) { 224 case DeviceTiming: 225 deviceTiming = pkt->get<uint8_t>(); 226 break; 227 case UDMAControl: 228 udmaControl = pkt->get<uint8_t>(); 229 break; 230 case IDEConfig: 231 replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>()); 232 break; 233 case IDEConfig + 1: 234 replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>()); 235 break; 236 default: 237 panic("Invalid PCI configuration write " 238 "for size 1 offset: %#x!\n", offset); 239 } 240 DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n", 241 offset, (uint32_t)pkt->get<uint8_t>()); 242 break; 243 case sizeof(uint16_t): 244 switch (offset) { 245 case PrimaryTiming: 246 primaryTiming = pkt->get<uint16_t>(); 247 break; 248 case SecondaryTiming: 249 secondaryTiming = pkt->get<uint16_t>(); 250 break; 251 case UDMATiming: 252 udmaTiming = pkt->get<uint16_t>(); 253 break; 254 case IDEConfig: 255 ideConfig = pkt->get<uint16_t>(); 256 break; 257 default: 258 panic("Invalid PCI configuration write " 259 "for size 2 offset: %#x!\n", 260 offset); 261 } 262 DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n", 263 offset, (uint32_t)pkt->get<uint16_t>()); 264 break; 265 case sizeof(uint32_t): 266 panic("Write of unimplemented PCI config. register: %x\n", offset); 267 break; 268 default: 269 panic("invalid access size(?) for PCI configspace!\n"); 270 } 271 pkt->makeAtomicResponse(); 272 } 273 274 /* Trap command register writes and enable IO/BM as appropriate as well as 275 * BARs. */ 276 switch(offset) { 277 case PCI0_BASE_ADDR0: 278 if (BARAddrs[0] != 0) 279 primary.cmdAddr = BARAddrs[0]; 280 break; 281 282 case PCI0_BASE_ADDR1: 283 if (BARAddrs[1] != 0) 284 primary.ctrlAddr = BARAddrs[1]; 285 break; 286 287 case PCI0_BASE_ADDR2: 288 if (BARAddrs[2] != 0) 289 secondary.cmdAddr = BARAddrs[2]; 290 break; 291 292 case PCI0_BASE_ADDR3: 293 if (BARAddrs[3] != 0) 294 secondary.ctrlAddr = BARAddrs[3]; 295 break; 296 297 case PCI0_BASE_ADDR4: 298 if (BARAddrs[4] != 0) 299 bmiAddr = BARAddrs[4]; 300 break; 301 302 case PCI_COMMAND: 303 ioEnabled = (config.command & htole(PCI_CMD_IOSE)); 304 bmEnabled = (config.command & htole(PCI_CMD_BME)); 305 break; 306 } 307 return configDelay; 308} 309 310void 311IdeController::Channel::accessCommand(Addr offset, 312 int size, uint8_t *data, bool read) 313{ 314 const Addr SelectOffset = 6; 315 const uint8_t SelectDevBit = 0x10; 316 317 if (!read && offset == SelectOffset) 318 select(*data & SelectDevBit); 319 320 if (selected == NULL) { 321 assert(size == sizeof(uint8_t)); 322 *data = 0; 323 } else if (read) { 324 selected->readCommand(offset, size, data); 325 } else { 326 selected->writeCommand(offset, size, data); 327 } 328} 329 330void 331IdeController::Channel::accessControl(Addr offset, 332 int size, uint8_t *data, bool read) 333{ 334 if (selected == NULL) { 335 assert(size == sizeof(uint8_t)); 336 *data = 0; 337 } else if (read) { 338 selected->readControl(offset, size, data); 339 } else { 340 selected->writeControl(offset, size, data); 341 } 342} 343 344void 345IdeController::Channel::accessBMI(Addr offset, 346 int size, uint8_t *data, bool read) 347{ 348 assert(offset + size <= sizeof(BMIRegs)); 349 if (read) { 350 memcpy(data, (uint8_t *)&bmiRegs + offset, size); 351 } else { 352 switch (offset) { 353 case BMICommand: 354 { 355 if (size != sizeof(uint8_t)) 356 panic("Invalid BMIC write size: %x\n", size); 357 358 BMICommandReg oldVal = bmiRegs.command; 359 BMICommandReg newVal = *data; 360 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; 364 365 if (oldVal.startStop != newVal.startStop) { 366 if (selected == NULL) 367 panic("DMA start for disk which does not exist\n"); 368 369 if (oldVal.startStop) { 370 DPRINTF(IdeCtrl, "Stopping DMA transfer\n"); 371 bmiRegs.status.active = 0; 372 373 selected->abortDma(); 374 } else { 375 DPRINTF(IdeCtrl, "Starting DMA transfer\n"); 376 bmiRegs.status.active = 1; 377 378 selected->startDma(letoh(bmiRegs.bmidtp)); 379 } 380 } 381 382 bmiRegs.command = newVal; 383 } 384 break; 385 case BMIStatus: 386 { 387 if (size != sizeof(uint8_t)) 388 panic("Invalid BMIS write size: %x\n", size); 389 390 BMIStatusReg oldVal = bmiRegs.status; 391 BMIStatusReg newVal = *data; 392 393 // the BMIDEA bit is read only 394 newVal.active = oldVal.active; 395 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? 399 else 400 newVal.intStatus = oldVal.intStatus; 401 if (oldVal.dmaError && newVal.dmaError) 402 newVal.dmaError = 0; 403 else 404 newVal.dmaError = oldVal.dmaError; 405 406 bmiRegs.status = newVal; 407 } 408 break; 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); 413 break; 414 default: 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); 419 } 420 } 421} 422 423void 424IdeController::dispatchAccess(PacketPtr pkt, bool read) 425{ 426 pkt->allocate(); 427 if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4) 428 panic("Bad IDE read size: %d\n", pkt->getSize()); 429 430 if (!ioEnabled) { 431 pkt->makeAtomicResponse(); 432 DPRINTF(IdeCtrl, "io not enabled\n"); 433 return; 434 } 435 436 Addr addr = pkt->getAddr(); 437 int size = pkt->getSize(); 438 uint8_t *dataPtr = pkt->getPtr<uint8_t>(); 439 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) 458 return; 459 addr -= bmiAddr; 460 if (addr < sizeof(Channel::BMIRegs)) { 461 primary.accessBMI(addr, size, dataPtr, read); 462 } else { 463 addr -= sizeof(Channel::BMIRegs); 464 secondary.accessBMI(addr, size, dataPtr, read); 465 } 466 } else { 467 panic("IDE controller access to invalid address: %#x\n", addr); 468 } 469 470 uint32_t data; 471 if (pkt->getSize() == 1) 472 data = pkt->get<uint8_t>(); 473 else if (pkt->getSize() == 2) 474 data = pkt->get<uint16_t>(); 475 else 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); 479 480 pkt->makeAtomicResponse(); 481} 482 483Tick 484IdeController::read(PacketPtr pkt) 485{ 486 dispatchAccess(pkt, true); 487 return pioDelay; 488} 489 490Tick 491IdeController::write(PacketPtr pkt) 492{ 493 dispatchAccess(pkt, false); 494 return pioDelay; 495} 496 497void 498IdeController::serialize(std::ostream &os) 499{ 500 // Serialize the PciDev base class 501 PciDev::serialize(os); 502 503 // Serialize channels 504 primary.serialize(os); 505 secondary.serialize(os); 506 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); 514 515 // Serialize internal state 516 SERIALIZE_SCALAR(ioEnabled); 517 SERIALIZE_SCALAR(bmEnabled); 518} 519 520void 521IdeController::Channel::serialize(std::ostream &os) 522{ 523 SERIALIZE_SCALAR(cmdAddr); 524 SERIALIZE_SCALAR(cmdSize); 525 SERIALIZE_SCALAR(ctrlAddr); 526 SERIALIZE_SCALAR(ctrlSize); 527 SERIALIZE_SCALAR((uint8_t)bmiRegs.command); 528 SERIALIZE_SCALAR(bmiRegs.reserved0); 529 SERIALIZE_SCALAR((uint8_t)bmiRegs.status); 530 SERIALIZE_SCALAR(bmiRegs.reserved1); 531 SERIALIZE_SCALAR(bmiRegs.bmidtp); 532 SERIALIZE_SCALAR(selectBit); 533} 534 535void 536IdeController::unserialize(Checkpoint *cp, const std::string §ion) 537{ 538 // Unserialize the PciDev base class 539 PciDev::unserialize(cp, section); 540 541 // Unserialize channels 542 primary.unserialize(cp, section); 543 secondary.unserialize(cp, section); 544 545 // Unserialize config registers 546 UNSERIALIZE_SCALAR(primaryTiming); 547 UNSERIALIZE_SCALAR(secondaryTiming); 548 UNSERIALIZE_SCALAR(deviceTiming); 549 UNSERIALIZE_SCALAR(udmaControl); 550 UNSERIALIZE_SCALAR(udmaTiming); 551 UNSERIALIZE_SCALAR(ideConfig); 552 553 // Unserialize internal state 554 UNSERIALIZE_SCALAR(ioEnabled); 555 UNSERIALIZE_SCALAR(bmEnabled); 556} 557 558void 559IdeController::Channel::unserialize( 560 Checkpoint *cp, const std::string §ion) 561{ 562 uint8_t temp; 563 UNSERIALIZE_SCALAR(cmdAddr); 564 UNSERIALIZE_SCALAR(cmdSize); 565 UNSERIALIZE_SCALAR(ctrlAddr); 566 UNSERIALIZE_SCALAR(ctrlSize); 567 UNSERIALIZE_SCALAR(temp); 568 bmiRegs.command = temp; 569 UNSERIALIZE_SCALAR(bmiRegs.reserved0); 570 UNSERIALIZE_SCALAR(temp); 571 bmiRegs.status = temp; 572 UNSERIALIZE_SCALAR(bmiRegs.reserved1); 573 UNSERIALIZE_SCALAR(bmiRegs.bmidtp); 574 UNSERIALIZE_SCALAR(selectBit); 575 select(selectBit); 576} 577 578IdeController * 579IdeControllerParams::create() 580{ 581 return new IdeController(this); 582} 583