mem: Remove redundant Packet::allocate calls
[gem5.git] / src / dev / ide_ctrl.cc
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
58 using std::string;
59
60 // Bus master IDE registers
61 enum BMIRegOffset {
62 BMICommand = 0x0,
63 BMIStatus = 0x2,
64 BMIDescTablePtr = 0x4
65 };
66
67 // PCI config space registers
68 enum ConfRegOffset {
69 PrimaryTiming = 0x40,
70 SecondaryTiming = 0x42,
71 DeviceTiming = 0x44,
72 UDMAControl = 0x48,
73 UDMATiming = 0x4A,
74 IDEConfig = 0x54
75 };
76
77 static const uint16_t timeRegWithDecodeEn = 0x8000;
78
79 IdeController::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
90 IdeController::Channel::~Channel()
91 {
92 }
93
94 IdeController::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
137 bool
138 IdeController::isDiskSelected(IdeDisk *diskPtr)
139 {
140 return (primary.selected == diskPtr || secondary.selected == diskPtr);
141 }
142
143 void
144 IdeController::intrPost()
145 {
146 primary.bmiRegs.status.intStatus = 1;
147 PciDevice::intrPost();
148 }
149
150 void
151 IdeController::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
167 Tick
168 IdeController::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 switch (pkt->getSize()) {
176 case sizeof(uint8_t):
177 switch (offset) {
178 case DeviceTiming:
179 pkt->set<uint8_t>(deviceTiming);
180 break;
181 case UDMAControl:
182 pkt->set<uint8_t>(udmaControl);
183 break;
184 case PrimaryTiming + 1:
185 pkt->set<uint8_t>(bits(htole(primaryTiming), 15, 8));
186 break;
187 case SecondaryTiming + 1:
188 pkt->set<uint8_t>(bits(htole(secondaryTiming), 15, 8));
189 break;
190 case IDEConfig:
191 pkt->set<uint8_t>(bits(htole(ideConfig), 7, 0));
192 break;
193 case IDEConfig + 1:
194 pkt->set<uint8_t>(bits(htole(ideConfig), 15, 8));
195 break;
196 default:
197 panic("Invalid PCI configuration read for size 1 at offset: %#x!\n",
198 offset);
199 }
200 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 1 data: %#x\n", offset,
201 (uint32_t)pkt->get<uint8_t>());
202 break;
203 case sizeof(uint16_t):
204 switch (offset) {
205 case PrimaryTiming:
206 pkt->set<uint16_t>(primaryTiming);
207 break;
208 case SecondaryTiming:
209 pkt->set<uint16_t>(secondaryTiming);
210 break;
211 case UDMATiming:
212 pkt->set<uint16_t>(udmaTiming);
213 break;
214 case IDEConfig:
215 pkt->set<uint16_t>(ideConfig);
216 break;
217 default:
218 panic("Invalid PCI configuration read for size 2 offset: %#x!\n",
219 offset);
220 }
221 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 2 data: %#x\n", offset,
222 (uint32_t)pkt->get<uint16_t>());
223 break;
224 case sizeof(uint32_t):
225 if (offset == IDEConfig)
226 pkt->set<uint32_t>(ideConfig);
227 else
228 panic("No 32bit reads implemented for this device.");
229 DPRINTF(IdeCtrl, "PCI read offset: %#x size: 4 data: %#x\n", offset,
230 (uint32_t)pkt->get<uint32_t>());
231 break;
232 default:
233 panic("invalid access size(?) for PCI configspace!\n");
234 }
235 pkt->makeAtomicResponse();
236 return configDelay;
237 }
238
239
240 Tick
241 IdeController::writeConfig(PacketPtr pkt)
242 {
243 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
244 if (offset < PCI_DEVICE_SPECIFIC) {
245 PciDevice::writeConfig(pkt);
246 } else {
247 switch (pkt->getSize()) {
248 case sizeof(uint8_t):
249 switch (offset) {
250 case DeviceTiming:
251 deviceTiming = pkt->get<uint8_t>();
252 break;
253 case UDMAControl:
254 udmaControl = pkt->get<uint8_t>();
255 break;
256 case IDEConfig:
257 replaceBits(ideConfig, 7, 0, pkt->get<uint8_t>());
258 break;
259 case IDEConfig + 1:
260 replaceBits(ideConfig, 15, 8, pkt->get<uint8_t>());
261 break;
262 default:
263 panic("Invalid PCI configuration write "
264 "for size 1 offset: %#x!\n", offset);
265 }
266 DPRINTF(IdeCtrl, "PCI write offset: %#x size: 1 data: %#x\n",
267 offset, (uint32_t)pkt->get<uint8_t>());
268 break;
269 case sizeof(uint16_t):
270 switch (offset) {
271 case PrimaryTiming:
272 primaryTiming = pkt->get<uint16_t>();
273 break;
274 case SecondaryTiming:
275 secondaryTiming = pkt->get<uint16_t>();
276 break;
277 case UDMATiming:
278 udmaTiming = pkt->get<uint16_t>();
279 break;
280 case IDEConfig:
281 ideConfig = pkt->get<uint16_t>();
282 break;
283 default:
284 panic("Invalid PCI configuration write "
285 "for size 2 offset: %#x!\n",
286 offset);
287 }
288 DPRINTF(IdeCtrl, "PCI write offset: %#x size: 2 data: %#x\n",
289 offset, (uint32_t)pkt->get<uint16_t>());
290 break;
291 case sizeof(uint32_t):
292 if (offset == IDEConfig)
293 ideConfig = pkt->get<uint32_t>();
294 else
295 panic("Write of unimplemented PCI config. register: %x\n", offset);
296 break;
297 default:
298 panic("invalid access size(?) for PCI configspace!\n");
299 }
300 pkt->makeAtomicResponse();
301 }
302
303 /* Trap command register writes and enable IO/BM as appropriate as well as
304 * BARs. */
305 switch(offset) {
306 case PCI0_BASE_ADDR0:
307 if (BARAddrs[0] != 0)
308 primary.cmdAddr = BARAddrs[0];
309 break;
310
311 case PCI0_BASE_ADDR1:
312 if (BARAddrs[1] != 0)
313 primary.ctrlAddr = BARAddrs[1];
314 break;
315
316 case PCI0_BASE_ADDR2:
317 if (BARAddrs[2] != 0)
318 secondary.cmdAddr = BARAddrs[2];
319 break;
320
321 case PCI0_BASE_ADDR3:
322 if (BARAddrs[3] != 0)
323 secondary.ctrlAddr = BARAddrs[3];
324 break;
325
326 case PCI0_BASE_ADDR4:
327 if (BARAddrs[4] != 0)
328 bmiAddr = BARAddrs[4];
329 break;
330
331 case PCI_COMMAND:
332 DPRINTF(IdeCtrl, "Writing to PCI Command val: %#x\n", config.command);
333 ioEnabled = (config.command & htole(PCI_CMD_IOSE));
334 bmEnabled = (config.command & htole(PCI_CMD_BME));
335 break;
336 }
337 return configDelay;
338 }
339
340 void
341 IdeController::Channel::accessCommand(Addr offset,
342 int size, uint8_t *data, bool read)
343 {
344 const Addr SelectOffset = 6;
345 const uint8_t SelectDevBit = 0x10;
346
347 if (!read && offset == SelectOffset)
348 select(*data & SelectDevBit);
349
350 if (selected == NULL) {
351 assert(size == sizeof(uint8_t));
352 *data = 0;
353 } else if (read) {
354 selected->readCommand(offset, size, data);
355 } else {
356 selected->writeCommand(offset, size, data);
357 }
358 }
359
360 void
361 IdeController::Channel::accessControl(Addr offset,
362 int size, uint8_t *data, bool read)
363 {
364 if (selected == NULL) {
365 assert(size == sizeof(uint8_t));
366 *data = 0;
367 } else if (read) {
368 selected->readControl(offset, size, data);
369 } else {
370 selected->writeControl(offset, size, data);
371 }
372 }
373
374 void
375 IdeController::Channel::accessBMI(Addr offset,
376 int size, uint8_t *data, bool read)
377 {
378 assert(offset + size <= sizeof(BMIRegs));
379 if (read) {
380 memcpy(data, (uint8_t *)&bmiRegs + offset, size);
381 } else {
382 switch (offset) {
383 case BMICommand:
384 {
385 if (size != sizeof(uint8_t))
386 panic("Invalid BMIC write size: %x\n", size);
387
388 BMICommandReg oldVal = bmiRegs.command;
389 BMICommandReg newVal = *data;
390
391 // if a DMA transfer is in progress, R/W control cannot change
392 if (oldVal.startStop && oldVal.rw != newVal.rw)
393 oldVal.rw = newVal.rw;
394
395 if (oldVal.startStop != newVal.startStop) {
396 if (selected == NULL)
397 panic("DMA start for disk which does not exist\n");
398
399 if (oldVal.startStop) {
400 DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
401 bmiRegs.status.active = 0;
402
403 selected->abortDma();
404 } else {
405 DPRINTF(IdeCtrl, "Starting DMA transfer\n");
406 bmiRegs.status.active = 1;
407
408 selected->startDma(letoh(bmiRegs.bmidtp));
409 }
410 }
411
412 bmiRegs.command = newVal;
413 }
414 break;
415 case BMIStatus:
416 {
417 if (size != sizeof(uint8_t))
418 panic("Invalid BMIS write size: %x\n", size);
419
420 BMIStatusReg oldVal = bmiRegs.status;
421 BMIStatusReg newVal = *data;
422
423 // the BMIDEA bit is read only
424 newVal.active = oldVal.active;
425
426 // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
427 if ((oldVal.intStatus == 1) && (newVal.intStatus == 1)) {
428 newVal.intStatus = 0; // clear the interrupt?
429 } else {
430 // Assigning two bitunion fields to each other does not
431 // work as intended, so we need to use this temporary variable
432 // to get around the bug.
433 uint8_t tmp = oldVal.intStatus;
434 newVal.intStatus = tmp;
435 }
436 if ((oldVal.dmaError == 1) && (newVal.dmaError == 1)) {
437 newVal.dmaError = 0;
438 } else {
439 uint8_t tmp = oldVal.dmaError;
440 newVal.dmaError = tmp;
441 }
442
443 bmiRegs.status = newVal;
444 }
445 break;
446 case BMIDescTablePtr:
447 if (size != sizeof(uint32_t))
448 panic("Invalid BMIDTP write size: %x\n", size);
449 bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3);
450 break;
451 default:
452 if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
453 size != sizeof(uint32_t))
454 panic("IDE controller write of invalid write size: %x\n", size);
455 memcpy((uint8_t *)&bmiRegs + offset, data, size);
456 }
457 }
458 }
459
460 void
461 IdeController::dispatchAccess(PacketPtr pkt, bool read)
462 {
463 if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
464 panic("Bad IDE read size: %d\n", pkt->getSize());
465
466 if (!ioEnabled) {
467 pkt->makeAtomicResponse();
468 DPRINTF(IdeCtrl, "io not enabled\n");
469 return;
470 }
471
472 Addr addr = pkt->getAddr();
473 int size = pkt->getSize();
474 uint8_t *dataPtr = pkt->getPtr<uint8_t>();
475
476 if (addr >= primary.cmdAddr &&
477 addr < (primary.cmdAddr + primary.cmdSize)) {
478 addr -= primary.cmdAddr;
479 // linux may have shifted the address by ioShift,
480 // here we shift it back, similarly for ctrlOffset.
481 addr >>= ioShift;
482 primary.accessCommand(addr, size, dataPtr, read);
483 } else if (addr >= primary.ctrlAddr &&
484 addr < (primary.ctrlAddr + primary.ctrlSize)) {
485 addr -= primary.ctrlAddr;
486 addr += ctrlOffset;
487 primary.accessControl(addr, size, dataPtr, read);
488 } else if (addr >= secondary.cmdAddr &&
489 addr < (secondary.cmdAddr + secondary.cmdSize)) {
490 addr -= secondary.cmdAddr;
491 secondary.accessCommand(addr, size, dataPtr, read);
492 } else if (addr >= secondary.ctrlAddr &&
493 addr < (secondary.ctrlAddr + secondary.ctrlSize)) {
494 addr -= secondary.ctrlAddr;
495 secondary.accessControl(addr, size, dataPtr, read);
496 } else if (addr >= bmiAddr && addr < (bmiAddr + bmiSize)) {
497 if (!read && !bmEnabled)
498 return;
499 addr -= bmiAddr;
500 if (addr < sizeof(Channel::BMIRegs)) {
501 primary.accessBMI(addr, size, dataPtr, read);
502 } else {
503 addr -= sizeof(Channel::BMIRegs);
504 secondary.accessBMI(addr, size, dataPtr, read);
505 }
506 } else {
507 panic("IDE controller access to invalid address: %#x\n", addr);
508 }
509
510 #ifndef NDEBUG
511 uint32_t data;
512 if (pkt->getSize() == 1)
513 data = pkt->get<uint8_t>();
514 else if (pkt->getSize() == 2)
515 data = pkt->get<uint16_t>();
516 else
517 data = pkt->get<uint32_t>();
518 DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
519 read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
520 #endif
521
522 pkt->makeAtomicResponse();
523 }
524
525 Tick
526 IdeController::read(PacketPtr pkt)
527 {
528 dispatchAccess(pkt, true);
529 return pioDelay;
530 }
531
532 Tick
533 IdeController::write(PacketPtr pkt)
534 {
535 dispatchAccess(pkt, false);
536 return pioDelay;
537 }
538
539 void
540 IdeController::serialize(std::ostream &os)
541 {
542 // Serialize the PciDevice base class
543 PciDevice::serialize(os);
544
545 // Serialize channels
546 primary.serialize("primary", os);
547 secondary.serialize("secondary", os);
548
549 // Serialize config registers
550 SERIALIZE_SCALAR(primaryTiming);
551 SERIALIZE_SCALAR(secondaryTiming);
552 SERIALIZE_SCALAR(deviceTiming);
553 SERIALIZE_SCALAR(udmaControl);
554 SERIALIZE_SCALAR(udmaTiming);
555 SERIALIZE_SCALAR(ideConfig);
556
557 // Serialize internal state
558 SERIALIZE_SCALAR(ioEnabled);
559 SERIALIZE_SCALAR(bmEnabled);
560 SERIALIZE_SCALAR(bmiAddr);
561 SERIALIZE_SCALAR(bmiSize);
562 }
563
564 void
565 IdeController::Channel::serialize(const std::string &base, std::ostream &os)
566 {
567 paramOut(os, base + ".cmdAddr", cmdAddr);
568 paramOut(os, base + ".cmdSize", cmdSize);
569 paramOut(os, base + ".ctrlAddr", ctrlAddr);
570 paramOut(os, base + ".ctrlSize", ctrlSize);
571 uint8_t command = bmiRegs.command;
572 paramOut(os, base + ".bmiRegs.command", command);
573 paramOut(os, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
574 uint8_t status = bmiRegs.status;
575 paramOut(os, base + ".bmiRegs.status", status);
576 paramOut(os, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
577 paramOut(os, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
578 paramOut(os, base + ".selectBit", selectBit);
579 }
580
581 void
582 IdeController::unserialize(Checkpoint *cp, const std::string &section)
583 {
584 // Unserialize the PciDevice base class
585 PciDevice::unserialize(cp, section);
586
587 // Unserialize channels
588 primary.unserialize("primary", cp, section);
589 secondary.unserialize("secondary", cp, section);
590
591 // Unserialize config registers
592 UNSERIALIZE_SCALAR(primaryTiming);
593 UNSERIALIZE_SCALAR(secondaryTiming);
594 UNSERIALIZE_SCALAR(deviceTiming);
595 UNSERIALIZE_SCALAR(udmaControl);
596 UNSERIALIZE_SCALAR(udmaTiming);
597 UNSERIALIZE_SCALAR(ideConfig);
598
599 // Unserialize internal state
600 UNSERIALIZE_SCALAR(ioEnabled);
601 UNSERIALIZE_SCALAR(bmEnabled);
602 UNSERIALIZE_SCALAR(bmiAddr);
603 UNSERIALIZE_SCALAR(bmiSize);
604 }
605
606 void
607 IdeController::Channel::unserialize(const std::string &base, Checkpoint *cp,
608 const std::string &section)
609 {
610 paramIn(cp, section, base + ".cmdAddr", cmdAddr);
611 paramIn(cp, section, base + ".cmdSize", cmdSize);
612 paramIn(cp, section, base + ".ctrlAddr", ctrlAddr);
613 paramIn(cp, section, base + ".ctrlSize", ctrlSize);
614 uint8_t command;
615 paramIn(cp, section, base +".bmiRegs.command", command);
616 bmiRegs.command = command;
617 paramIn(cp, section, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
618 uint8_t status;
619 paramIn(cp, section, base + ".bmiRegs.status", status);
620 bmiRegs.status = status;
621 paramIn(cp, section, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
622 paramIn(cp, section, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
623 paramIn(cp, section, base + ".selectBit", selectBit);
624 select(selectBit);
625 }
626
627 IdeController *
628 IdeControllerParams::create()
629 {
630 return new IdeController(this);
631 }