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