gem5  v22.1.0.0
ide_ctrl.cc
Go to the documentation of this file.
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 
41 #include "dev/storage/ide_ctrl.hh"
42 
43 #include <string>
44 
45 #include "base/cprintf.hh"
46 #include "debug/IdeCtrl.hh"
47 #include "dev/storage/ide_disk.hh"
48 #include "mem/packet.hh"
49 #include "mem/packet_access.hh"
50 #include "params/IdeController.hh"
51 #include "sim/byteswap.hh"
52 
53 namespace gem5
54 {
55 
56 // Bus master IDE registers
58 {
59  BMICommand = 0x0,
60  BMIStatus = 0x2,
61  BMIDescTablePtr = 0x4
62 };
63 
64 IdeController::Channel::Channel(std::string new_name, IdeController *new_ctrl,
65  bool new_primary) :
66  Named(new_name), ctrl(new_ctrl), primary(new_primary)
67 {
68  bmiRegs.reset();
69  bmiRegs.status.dmaCap0 = 1;
70  bmiRegs.status.dmaCap1 = 1;
71 }
72 
74  : PciDevice(p), configSpaceRegs(name() + ".config_space_regs"),
75  primary(name() + ".primary", this, true),
76  secondary(name() + ".secondary", this, false),
77  ioShift(p.io_shift), ctrlOffset(p.ctrl_offset)
78 {
79  panic_if(params().disks.size() > 4,
80  "IDE controllers support a maximum of 4 devices attached!");
81 
82  // Assign the disks to channels
83  for (int i = 0; i < params().disks.size(); i++) {
84  auto *disk = params().disks[i];
85  auto &channel = (i < 2) ? primary : secondary;
86 
87  if (!disk)
88  continue;
89 
90  if (i % 2 == 0)
91  channel.setDevice0(disk);
92  else
93  channel.setDevice1(disk);
94 
95  // Arbitrarily set the chunk size to 4K.
96  disk->setChannel(&channel, 4 * 1024);
97  }
98 
99  primary.select(false);
100  secondary.select(false);
101 }
102 
103 void
105 {
106  SERIALIZE_SCALAR(primaryTiming);
107  SERIALIZE_SCALAR(secondaryTiming);
108  SERIALIZE_SCALAR(deviceTiming);
109  SERIALIZE_SCALAR(udmaControl);
110  SERIALIZE_SCALAR(udmaTiming);
111 }
112 
113 void
115 {
116  UNSERIALIZE_SCALAR(primaryTiming);
117  UNSERIALIZE_SCALAR(secondaryTiming);
118  UNSERIALIZE_SCALAR(deviceTiming);
119  UNSERIALIZE_SCALAR(udmaControl);
120  UNSERIALIZE_SCALAR(udmaTiming);
121 }
122 
123 void
125 {
126  bmiRegs.status.intStatus = 1;
127  _pendingInterrupt = true;
129 }
130 
131 void
133 {
134  bmiRegs.status.intStatus = 0;
135  _pendingInterrupt = false;
136  ctrl->clearInterrupt(isPrimary());
137 }
138 
139 void
141 {
142  auto &other = is_primary ? secondary : primary;
143  // If an interrupt isn't already posted for the other channel...
144  if (!other.pendingInterrupt())
146 }
147 
148 void
150 {
151  auto &other = is_primary ? secondary : primary;
152  // If the interrupt isn't still needed by the other channel...
153  if (!other.pendingInterrupt())
155 }
156 
157 Tick
159 {
160  int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
162  return PciDevice::readConfig(pkt);
163 
164  size_t size = pkt->getSize();
165 
166  configSpaceRegs.read(offset, pkt->getPtr<void>(), size);
167 
168  DPRINTF(IdeCtrl, "PCI read offset: %#x size: %d data: %#x\n", offset, size,
169  pkt->getUintX(ByteOrder::little));
170 
171  pkt->makeAtomicResponse();
172  return configDelay;
173 }
174 
175 
176 Tick
178 {
179  int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
180 
182  return PciDevice::writeConfig(pkt);
183 
184  size_t size = pkt->getSize();
185 
186  DPRINTF(IdeCtrl, "PCI write offset: %#x size: %d data: %#x\n",
187  offset, size, pkt->getUintX(ByteOrder::little));
188 
189  configSpaceRegs.write(offset, pkt->getConstPtr<void>(), size);
190 
191  pkt->makeAtomicResponse();
192  return configDelay;
193 }
194 
195 void
197  int size, uint8_t *data, bool read)
198 {
199  const Addr SelectOffset = 6;
200  const uint8_t SelectDevBit = 0x10;
201 
202  if (!read && offset == SelectOffset)
203  select(*data & SelectDevBit);
204 
205  if (selected() == NULL) {
206  assert(size == sizeof(uint8_t));
207  *data = 0;
208  } else if (read) {
209  selected()->readCommand(offset, size, data);
210  } else {
211  selected()->writeCommand(offset, size, data);
212  }
213 }
214 
215 void
217  int size, uint8_t *data, bool read)
218 {
219  if (selected() == NULL) {
220  assert(size == sizeof(uint8_t));
221  *data = 0;
222  } else if (read) {
223  selected()->readControl(offset, size, data);
224  } else {
225  selected()->writeControl(offset, size, data);
226  }
227 }
228 
229 void
231  int size, uint8_t *data, bool read)
232 {
233  assert(offset + size <= sizeof(BMIRegs));
234  if (read) {
235  memcpy(data, (uint8_t *)&bmiRegs + offset, size);
236  } else {
237  switch (offset) {
238  case BMICommand:
239  {
240  if (size != sizeof(uint8_t))
241  panic("Invalid BMIC write size: %x\n", size);
242 
243  BMICommandReg oldVal = bmiRegs.command;
244  BMICommandReg newVal = *data;
245 
246  // if a DMA transfer is in progress, R/W control cannot change
247  if (oldVal.startStop && oldVal.rw != newVal.rw)
248  oldVal.rw = newVal.rw;
249 
250  if (oldVal.startStop != newVal.startStop) {
251  if (selected() == NULL)
252  panic("DMA start for disk which does not exist\n");
253 
254  if (oldVal.startStop) {
255  DPRINTF(IdeCtrl, "Stopping DMA transfer\n");
256  bmiRegs.status.active = 0;
257 
258  selected()->abortDma();
259  } else {
260  DPRINTF(IdeCtrl, "Starting DMA transfer\n");
261  bmiRegs.status.active = 1;
262 
263  selected()->startDma(letoh(bmiRegs.bmidtp));
264  }
265  }
266 
267  bmiRegs.command = newVal;
268  }
269  break;
270  case BMIStatus:
271  {
272  if (size != sizeof(uint8_t))
273  panic("Invalid BMIS write size: %x\n", size);
274 
275  BMIStatusReg oldVal = bmiRegs.status;
276  BMIStatusReg newVal = *data;
277 
278  // the BMIDEA bit is read only
279  newVal.active = oldVal.active;
280 
281  // to reset (set 0) IDEINTS and IDEDMAE, write 1 to each
282  if ((oldVal.intStatus == 1) && (newVal.intStatus == 1)) {
283  newVal.intStatus = 0; // clear the interrupt?
284  } else {
285  // Assigning two bitunion fields to each other does not
286  // work as intended, so we need to use this temporary
287  // variable to get around the bug.
288  uint8_t tmp = oldVal.intStatus;
289  newVal.intStatus = tmp;
290  }
291  if ((oldVal.dmaError == 1) && (newVal.dmaError == 1)) {
292  newVal.dmaError = 0;
293  } else {
294  uint8_t tmp = oldVal.dmaError;
295  newVal.dmaError = tmp;
296  }
297 
298  bmiRegs.status = newVal;
299  }
300  break;
301  case BMIDescTablePtr:
302  if (size != sizeof(uint32_t))
303  panic("Invalid BMIDTP write size: %x\n", size);
304  bmiRegs.bmidtp = htole(*(uint32_t *)data & ~0x3);
305  break;
306  default:
307  if (size != sizeof(uint8_t) && size != sizeof(uint16_t) &&
308  size != sizeof(uint32_t)) {
309  panic("IDE controller write of invalid size: %x\n", size);
310  }
311  memcpy((uint8_t *)&bmiRegs + offset, data, size);
312  }
313  }
314 }
315 
316 void
318 {
319  if (pkt->getSize() != 1 && pkt->getSize() != 2 && pkt->getSize() !=4)
320  panic("Bad IDE read size: %d\n", pkt->getSize());
321 
322  Addr addr = pkt->getAddr();
323  int size = pkt->getSize();
324  uint8_t *dataPtr = pkt->getPtr<uint8_t>();
325 
326  int bar_num;
327  Addr offset;
328  panic_if(!getBAR(addr, bar_num, offset),
329  "IDE controller access to invalid address: %#x.", addr);
330 
331  switch (bar_num) {
332  case 0:
333  // linux may have shifted the address by ioShift,
334  // here we shift it back, similarly for ctrlOffset.
335  offset >>= ioShift;
336  primary.accessCommand(offset, size, dataPtr, read);
337  break;
338  case 1:
339  offset += ctrlOffset;
340  primary.accessControl(offset, size, dataPtr, read);
341  break;
342  case 2:
343  secondary.accessCommand(offset, size, dataPtr, read);
344  break;
345  case 3:
346  secondary.accessControl(offset, size, dataPtr, read);
347  break;
348  case 4:
349  {
350  PciCommandRegister command = letoh(config.command);
351  if (!read && !command.busMaster)
352  return;
353 
354  if (offset < sizeof(Channel::BMIRegs)) {
355  primary.accessBMI(offset, size, dataPtr, read);
356  } else {
357  offset -= sizeof(Channel::BMIRegs);
358  secondary.accessBMI(offset, size, dataPtr, read);
359  }
360  }
361  }
362 
363 #ifndef NDEBUG
364  uint32_t data;
365  if (pkt->getSize() == 1)
366  data = pkt->getLE<uint8_t>();
367  else if (pkt->getSize() == 2)
368  data = pkt->getLE<uint16_t>();
369  else
370  data = pkt->getLE<uint32_t>();
371  DPRINTF(IdeCtrl, "%s from offset: %#x size: %#x data: %#x\n",
372  read ? "Read" : "Write", pkt->getAddr(), pkt->getSize(), data);
373 #endif
374 
375  pkt->makeAtomicResponse();
376 }
377 
378 void
380 {
381  bmiRegs.command.startStop = 0;
382  bmiRegs.status.active = 0;
383  bmiRegs.status.intStatus = 1;
384 }
385 
386 Tick
388 {
389  dispatchAccess(pkt, true);
390  return pioDelay;
391 }
392 
393 Tick
395 {
396  dispatchAccess(pkt, false);
397  return pioDelay;
398 }
399 
400 void
402 {
403  // Serialize the PciDevice base class
405 
406  // Serialize channels
407  primary.serialize("primary", cp);
408  secondary.serialize("secondary", cp);
409 
410  // Serialize config registers
411  configSpaceRegs.serialize(cp);
412 }
413 
414 void
416  CheckpointOut &cp) const
417 {
418  uint8_t command = bmiRegs.command;
419  paramOut(cp, base + ".bmiRegs.command", command);
420  paramOut(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
421  uint8_t status = bmiRegs.status;
422  paramOut(cp, base + ".bmiRegs.status", status);
423  paramOut(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
424  paramOut(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
425  paramOut(cp, base + ".selectBit", selectBit);
426 }
427 
428 void
430 {
431  // Unserialize the PciDevice base class
433 
434  // Unserialize channels
435  primary.unserialize("primary", cp);
436  secondary.unserialize("secondary", cp);
437 
438  // Unserialize config registers
439  configSpaceRegs.unserialize(cp);
440 }
441 
442 void
444 {
445  uint8_t command;
446  paramIn(cp, base +".bmiRegs.command", command);
447  bmiRegs.command = command;
448  paramIn(cp, base + ".bmiRegs.reserved0", bmiRegs.reserved0);
449  uint8_t status;
450  paramIn(cp, base + ".bmiRegs.status", status);
451  bmiRegs.status = status;
452  paramIn(cp, base + ".bmiRegs.reserved1", bmiRegs.reserved1);
453  paramIn(cp, base + ".bmiRegs.bmidtp", bmiRegs.bmidtp);
454  paramIn(cp, base + ".selectBit", selectBit);
455  select(selectBit);
456 }
457 
458 } // namespace gem5
#define DPRINTF(x,...)
Definition: trace.hh:186
const char data[]
DmaDeviceParams Params
Definition: dma_device.hh:209
void accessControl(Addr offset, int size, uint8_t *data, bool read)
Definition: ide_ctrl.cc:216
void select(bool select_device_1)
Definition: ide_ctrl.hh:168
void serialize(const std::string &base, std::ostream &os) const
Definition: ide_ctrl.cc:415
void accessCommand(Addr offset, int size, uint8_t *data, bool read)
Definition: ide_ctrl.cc:196
void setDevice0(IdeDisk *disk)
Definition: ide_ctrl.hh:138
void accessBMI(Addr offset, int size, uint8_t *data, bool read)
Definition: ide_ctrl.cc:230
void unserialize(const std::string &base, CheckpointIn &cp)
Definition: ide_ctrl.cc:443
struct gem5::IdeController::Channel::BMIRegs bmiRegs
Channel(std::string new_name, IdeController *new_ctrl, bool new_primary)
Definition: ide_ctrl.cc:64
Device model for an Intel PIIX4 IDE controller.
Definition: ide_ctrl.hh:53
virtual void postInterrupt(bool is_primary)
Definition: ide_ctrl.cc:140
virtual void clearInterrupt(bool is_primary)
Definition: ide_ctrl.cc:149
Tick read(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: ide_ctrl.cc:387
Tick write(PacketPtr pkt) override
Pure virtual function that the device must implement.
Definition: ide_ctrl.cc:394
IdeController(const Params &p)
Definition: ide_ctrl.cc:73
EndBitUnion(BMICommandReg) class ConfigSpaceRegs ConfigSpaceRegs configSpaceRegs
Registers used in device specific PCI configuration.
Definition: ide_ctrl.hh:67
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
Definition: ide_ctrl.cc:401
void dispatchAccess(PacketPtr pkt, bool read)
Definition: ide_ctrl.cc:317
uint32_t ctrlOffset
Definition: ide_ctrl.hh:194
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition: ide_ctrl.cc:429
Tick readConfig(PacketPtr pkt) override
Read from the PCI config space data that is stored locally.
Definition: ide_ctrl.cc:158
Tick writeConfig(PacketPtr pkt) override
Write to the PCI config space data that is stored locally.
Definition: ide_ctrl.cc:177
Interface for things with names.
Definition: named.hh:39
virtual std::string name() const
Definition: named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
T * getPtr()
get a pointer to the data ptr.
Definition: packet.hh:1212
Addr getAddr() const
Definition: packet.hh:805
unsigned getSize() const
Definition: packet.hh:815
uint64_t getUintX(ByteOrder endian) const
Get the data in the packet byte swapped from the specified endianness and zero-extended to 64 bits.
Definition: packet.cc:352
const T * getConstPtr() const
Definition: packet.hh:1221
void makeAtomicResponse()
Definition: packet.hh:1071
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
PCI device, base implementation is only config space.
Definition: device.hh:270
PCIConfig config
The current config space.
Definition: device.hh:275
void intrClear()
Definition: device.hh:365
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition: device.cc:464
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
Definition: device.cc:401
bool getBAR(Addr addr, int &num, Addr &offs)
Which base address register (if any) maps the given address?
Definition: device.hh:320
virtual Tick readConfig(PacketPtr pkt)
Read from the PCI config space data that is stored locally.
Definition: device.cc:212
virtual Tick writeConfig(PacketPtr pkt)
Write to the PCI config space data that is stored locally.
Definition: device.cc:283
void intrPost()
Definition: device.hh:364
Tick configDelay
Definition: device.hh:355
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:178
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:204
const Params & params() const
Definition: sim_object.hh:176
Device model for an IDE disk.
Bitfield< 7 > i
Definition: misc_types.hh:67
Bitfield< 23, 0 > offset
Definition: types.hh:144
Bitfield< 5, 0 > status
Definition: misc_types.hh:429
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 51, 12 > base
Definition: pagetable.hh:141
Bitfield< 3 > addr
Definition: types.hh:84
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
T letoh(T value)
Definition: byteswap.hh:173
std::ostream CheckpointOut
Definition: serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
Definition: types.cc:40
void unserialize(ThreadContext &tc, CheckpointIn &cp)
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
Definition: types.cc:72
BMIRegOffset
Definition: ide_ctrl.cc:58
@ BMICommand
Definition: ide_ctrl.cc:59
@ BMIDescTablePtr
Definition: ide_ctrl.cc:61
@ BMIStatus
Definition: ide_ctrl.cc:60
uint64_t Tick
Tick count type.
Definition: types.hh:58
T htole(T value)
Definition: byteswap.hh:172
void serialize(const ThreadContext &tc, CheckpointOut &cp)
Thread context serialization helpers.
Declaration of the Packet class.
#define PCI_DEVICE_SPECIFIC
Definition: pcireg.h:164
#define PCI_CONFIG_SIZE
Definition: pcireg.h:165
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
Simple PCI IDE controller with bus mastering capability and UDMA modeled after controller in the Inte...
Registers used for bus master interface.
Definition: ide_ctrl.hh:153

Generated on Wed Dec 21 2022 10:22:35 for gem5 by doxygen 1.9.1