gem5
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
base.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, 2016 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  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions are
16  * met: redistributions of source code must retain the above copyright
17  * notice, this list of conditions and the following disclaimer;
18  * redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution;
21  * neither the name of the copyright holders nor the names of its
22  * contributors may be used to endorse or promote products derived from
23  * this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  *
37  * Authors: Andreas Sandberg
38  */
39 
40 #include "dev/virtio/base.hh"
41 
42 #include "debug/VIO.hh"
43 #include "params/VirtIODeviceBase.hh"
44 #include "params/VirtIODummyDevice.hh"
45 
47  Index descIndex)
48  : memProxy(&_memProxy), queue(&_queue), _index(descIndex),
49  desc{0, 0, 0, 0}
50 {
51 }
52 
54 {
55  *this = std::forward<VirtDescriptor>(other);
56 }
57 
59 {
60 }
61 
64 {
65  memProxy = std::move(rhs.memProxy);
66  queue = std::move(rhs.queue);
67  _index = std::move(rhs._index);
68  desc = std::move(rhs.desc);
69 
70  return *this;
71 }
72 
73 void
75 {
76  const Addr vq_addr(queue->getAddress());
77  // Check if the queue has been initialized yet
78  if (vq_addr == 0)
79  return;
80 
81  assert(_index < queue->getSize());
82  const Addr desc_addr(vq_addr + sizeof(desc) * _index);
83  vring_desc guest_desc;
84  memProxy->readBlob(desc_addr, (uint8_t *)&guest_desc, sizeof(guest_desc));
85  desc = vtoh_legacy(guest_desc);
86  DPRINTF(VIO,
87  "VirtDescriptor(%i): Addr: 0x%x, Len: %i, Flags: 0x%x, "
88  "Next: 0x%x\n",
89  _index, desc.addr, desc.len, desc.flags, desc.next);
90 }
91 
92 void
94 {
95  VirtDescriptor *desc(this);
96  do {
97  desc->update();
98  } while ((desc = desc->next()) != NULL && desc != this);
99 
100  if (desc == this)
101  panic("Loop in descriptor chain!\n");
102 }
103 
104 void
106 {
107  if (!DTRACE(VIO))
108  return;
109 
110  DPRINTF(VIO, "Descriptor[%i]: "
111  "Addr: 0x%x, Len: %i, Flags: 0x%x, Next: 0x%x\n",
113 
114  if (isIncoming()) {
115  uint8_t data[desc.len];
116  read(0, data, desc.len);
117  DDUMP(VIO, data, desc.len);
118  }
119 }
120 
121 void
123 {
124  if (!DTRACE(VIO))
125  return;
126 
127  const VirtDescriptor *desc(this);
128  do {
129  desc->dump();
130  } while ((desc = desc->next()) != NULL);
131 }
132 
135 {
136  if (hasNext()) {
137  return queue->getDescriptor(desc.next);
138  } else {
139  return NULL;
140  }
141 }
142 
143 void
144 VirtDescriptor::read(size_t offset, uint8_t *dst, size_t size) const
145 {
146  DPRINTF(VIO, "VirtDescriptor(%p, 0x%x, %i)::read: offset: %i, dst: 0x%x, size: %i\n",
147  this, desc.addr, desc.len, offset, (long)dst, size);
148  assert(size <= desc.len - offset);
149  if (!isIncoming())
150  panic("Trying to read from outgoing buffer\n");
151 
152  memProxy->readBlob(desc.addr + offset, dst, size);
153 }
154 
155 void
156 VirtDescriptor::write(size_t offset, const uint8_t *src, size_t size)
157 {
158  DPRINTF(VIO, "VirtDescriptor(%p, 0x%x, %i)::write: offset: %i, src: 0x%x, size: %i\n",
159  this, desc.addr, desc.len, offset, (long)src, size);
160  assert(size <= desc.len - offset);
161  if (!isOutgoing())
162  panic("Trying to write to incoming buffer\n");
163 
164  memProxy->writeBlob(desc.addr + offset, const_cast<uint8_t *>(src), size);
165 }
166 
167 void
168 VirtDescriptor::chainRead(size_t offset, uint8_t *dst, size_t size) const
169 {
170  const VirtDescriptor *desc(this);
171  const size_t full_size(size);
172  do {
173  if (offset < desc->size()) {
174  const size_t chunk_size(std::min(desc->size() - offset, size));
175  desc->read(offset, dst, chunk_size);
176  dst += chunk_size;
177  size -= chunk_size;
178  offset = 0;
179  } else {
180  offset -= desc->size();
181  }
182  } while ((desc = desc->next()) != NULL && desc->isIncoming() && size > 0);
183 
184  if (size != 0) {
185  panic("Failed to read %i bytes from chain of %i bytes @ offset %i\n",
186  full_size, chainSize(), offset);
187  }
188 }
189 
190 void
191 VirtDescriptor::chainWrite(size_t offset, const uint8_t *src, size_t size)
192 {
193  VirtDescriptor *desc(this);
194  const size_t full_size(size);
195  do {
196  if (offset < desc->size()) {
197  const size_t chunk_size(std::min(desc->size() - offset, size));
198  desc->write(offset, src, chunk_size);
199  src += chunk_size;
200  size -= chunk_size;
201  offset = 0;
202  } else {
203  offset -= desc->size();
204  }
205  } while ((desc = desc->next()) != NULL && size > 0);
206 
207  if (size != 0) {
208  panic("Failed to write %i bytes into chain of %i bytes @ offset %i\n",
209  full_size, chainSize(), offset);
210  }
211 }
212 
213 size_t
215 {
216  size_t size(0);
217  const VirtDescriptor *desc(this);
218  do {
219  size += desc->size();
220  } while ((desc = desc->next()) != NULL);
221 
222  return size;
223 }
224 
225 
226 
228  : _size(size), _address(0), memProxy(proxy),
229  avail(proxy, size), used(proxy, size),
230  _last_avail(0)
231 {
232  descriptors.reserve(_size);
233  for (int i = 0; i < _size; ++i)
234  descriptors.emplace_back(proxy, *this, i);
235 }
236 
237 void
239 {
242 }
243 
244 void
246 {
247  Addr addr_in;
248 
249  paramIn(cp, "_address", addr_in);
251 
252  // Use the address setter to ensure that the ring buffer addresses
253  // are updated as well.
254  setAddress(addr_in);
255 }
256 
257 void
259 {
260  const Addr addr_avail(address + _size * sizeof(struct vring_desc));
261  const Addr addr_avail_end(addr_avail + sizeof(struct vring_avail) +
262  _size * sizeof(uint16_t));
263  const Addr addr_used((addr_avail_end + sizeof(uint16_t) +
264  (ALIGN_SIZE - 1)) & ~(ALIGN_SIZE - 1));
265  _address = address;
266  avail.setAddress(addr_avail);
267  used.setAddress(addr_used);
268 }
269 
272 {
273  avail.read();
274  DPRINTF(VIO, "consumeDescriptor: _last_avail: %i, avail.idx: %i (->%i)\n",
275  _last_avail, avail.header.index,
276  avail.ring[_last_avail % used.ring.size()]);
277  if (_last_avail == avail.header.index)
278  return NULL;
279 
281  ++_last_avail;
282 
284  d->updateChain();
285 
286  return d;
287 }
288 
289 void
291 {
292  used.readHeader();
293  DPRINTF(VIO, "produceDescriptor: dscIdx: %i, len: %i, used.idx: %i\n",
294  desc->index(), len, used.header.index);
295 
296  struct vring_used_elem &e(used.ring[used.header.index % used.ring.size()]);
297  e.id = desc->index();
298  e.len = len;
299  used.header.index += 1;
300  used.write();
301 }
302 
303 void
305 {
306  if (!DTRACE(VIO))
307  return;
308 
309  for (const VirtDescriptor &d : descriptors)
310  d.dump();
311 }
312 
313 void
315 {
316  DPRINTF(VIO, "onNotify\n");
317 
318  // Consume all pending descriptors from the input queue.
319  VirtDescriptor *d;
320  while ((d = consumeDescriptor()) != NULL)
322 }
323 
324 
326  size_t config_size, FeatureBits features)
327  : SimObject(params),
328  guestFeatures(0),
329  deviceId(id), configSize(config_size), deviceFeatures(features),
330  _deviceStatus(0), _queueSelect(0),
331  transKick(NULL)
332 {
333 }
334 
335 
337 {
338 }
339 
340 void
342 {
346  for (QueueID i = 0; i < _queues.size(); ++i)
347  _queues[i]->serializeSection(cp, csprintf("_queues.%i", i));
348 }
349 
350 void
352 {
356  for (QueueID i = 0; i < _queues.size(); ++i)
357  _queues[i]->unserializeSection(cp, csprintf("_queues.%i", i));
358 }
359 
360 void
362 {
363  _queueSelect = 0;
364  guestFeatures = 0;
365  _deviceStatus = 0;
366 
367  for (QueueID i = 0; i < _queues.size(); ++i)
368  _queues[i]->setAddress(0);
369 }
370 
371 void
373 {
374  DPRINTF(VIO, "onNotify: idx: %i\n", idx);
375  if (idx >= _queues.size()) {
376  panic("Guest tried to notify queue (%i), but only %i "
377  "queues registered.\n",
378  idx, _queues.size());
379  }
380  _queues[idx]->onNotify();
381 }
382 
383 void
385 {
386  DPRINTF(VIO, "Setting guest features: 0x%x\n", features);
387  if (~deviceFeatures & features) {
388  panic("Guest tried to enable unsupported features:\n"
389  "Device features: 0x%x\n"
390  "Requested features: 0x%x\n",
391  deviceFeatures, features);
392  }
393  guestFeatures = features;
394 }
395 
396 
397 void
399 {
401  DPRINTF(VIO, "ACK: %i, DRIVER: %i, DRIVER_OK: %i, FAILED: %i\n",
402  status.acknowledge, status.driver, status.driver_ok, status.failed);
403  if (status == 0)
404  reset();
405 }
406 
407 void
409 {
410  panic("Unhandled device config read (offset: 0x%x).\n", cfgOffset);
411 }
412 
413 void
415 {
416  panic("Unhandled device config write (offset: 0x%x).\n", cfgOffset);
417 }
418 
419 void
420 VirtIODeviceBase::readConfigBlob(PacketPtr pkt, Addr cfgOffset, const uint8_t *cfg)
421 {
422  const unsigned size(pkt->getSize());
423 
424  if (cfgOffset + size > configSize)
425  panic("Config read out of bounds.\n");
426 
427  pkt->makeResponse();
428  pkt->setData(const_cast<uint8_t *>(cfg) + cfgOffset);
429 }
430 
431 void
433 {
434  const unsigned size(pkt->getSize());
435 
436  if (cfgOffset + size > configSize)
437  panic("Config write out of bounds.\n");
438 
439  pkt->makeResponse();
440  pkt->writeData((uint8_t *)cfg + cfgOffset);
441 }
442 
443 
444 const VirtQueue &
446 {
447  if (_queueSelect >= _queues.size())
448  panic("Guest tried to access non-existing VirtQueue (%i).\n", _queueSelect);
449 
450  return *_queues[_queueSelect];
451 }
452 
453 VirtQueue &
455 {
456  if (_queueSelect >= _queues.size())
457  panic("Guest tried to access non-existing VirtQueue (%i).\n", _queueSelect);
458 
459  return *_queues[_queueSelect];
460 }
461 
462 void
464 {
466 }
467 
468 uint32_t
470 {
471  Addr address(getCurrentQueue().getAddress());
472  assert(!(address & ((1 >> VirtQueue::ALIGN_BITS) - 1)));
473  return address >> VirtQueue::ALIGN_BITS;
474 }
475 
476 void
478 {
479  _queues.push_back(&queue);
480 }
481 
482 
483 VirtIODummyDevice::VirtIODummyDevice(VirtIODummyDeviceParams *params)
484  : VirtIODeviceBase(params, ID_INVALID, 0, 0)
485 {
486 }
487 
489 VirtIODummyDeviceParams::create()
490 {
491  return new VirtIODummyDevice(this);
492 }
#define DPRINTF(x,...)
Definition: trace.hh:212
Base class for all VirtIO-based devices.
Definition: base.hh:570
void write(size_t offset, const uint8_t *src, size_t size)
Write to the contents of a descriptor.
Definition: base.cc:156
VirtDescriptor & operator=(VirtDescriptor &&rhs) noexcept
Definition: base.cc:63
void dump() const
Dump the contents of a queue.
Definition: base.cc:304
Bitfield< 30, 0 > index
void setAddress(Addr address)
Set the base address of this queue.
Definition: base.cc:258
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: base.cc:245
Bitfield< 7 > i
Definition: miscregs.hh:1378
~VirtDescriptor() noexcept
Definition: base.cc:58
#define panic(...)
Definition: misc.hh:153
SimObjectParams Params
Definition: sim_object.hh:110
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition: serialize.cc:585
bool hasNext() const
Is this descriptor chained to another descriptor?
Definition: base.hh:238
#define DDUMP(x, data, count)
Definition: trace.hh:211
Index index() const
Get the descriptor's index into the virtqueue.
Definition: base.hh:162
static const unsigned ALIGN_BITS
Page size used by VirtIO. It's hard-coded to 4096 bytes in the spec for historical reasons...
Definition: base.hh:436
void setGuestFeatures(FeatureBits features)
Set feature bits accepted by the guest driver.
Definition: base.cc:384
VirtDescriptor * getDescriptor(VirtDescriptor::Index index)
Get a pointer to a specific descriptor in the queue.
Definition: base.hh:359
void setAddress(Addr addr)
Set the base address of the VirtIO ring buffer.
Definition: base.hh:490
Bitfield< 23, 0 > offset
Definition: types.hh:149
void dumpChain() const
Dump the contents of a descriptor chain starting at this descriptor.
Definition: base.cc:122
void setDeviceStatus(DeviceStatus status)
Update device status and optionally reset device.
Definition: base.cc:398
bool isIncoming() const
Check if this is a read-only descriptor (incoming data).
Definition: base.hh:248
void writeData(uint8_t *p) const
Copy data from the packet to the provided block pointer, which is aligned to the given block size...
Definition: packet.hh:1052
virtual ~VirtIODeviceBase()
Definition: base.cc:336
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: base.cc:341
const char data[]
Definition: circlebuf.cc:43
void readHeader()
Update the ring buffer header with data from the guest.
Definition: base.hh:493
VirtDescriptor * consumeDescriptor()
Get an incoming descriptor chain from the queue.
Definition: base.cc:271
Bitfield< 5, 0 > status
Definition: miscregs.hh:1604
void dump() const
Dump the contents of a descriptor.
Definition: base.cc:105
void produceDescriptor(VirtDescriptor *desc, uint32_t len)
Send a descriptor chain to the guest.
Definition: base.cc:290
Addr _address
Base address of the queue.
Definition: base.hh:458
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:145
void writeConfigBlob(PacketPtr pkt, Addr cfgOffset, uint8_t *cfg)
Write configuration data to a device structure.
Definition: base.cc:432
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:161
DeviceStatus _deviceStatus
Status of the device.
Definition: base.hh:868
#define DTRACE(x)
Definition: trace.hh:210
void setData(const uint8_t *p)
Copy data into the packet from the provided pointer.
Definition: packet.hh:1024
QueueID _queueSelect
Queue select register (set by guest)
Definition: base.hh:871
std::vector< VirtDescriptor > descriptors
Vector of pre-created descriptors indexed by their index into the queue.
Definition: base.hh:557
void chainRead(size_t offset, uint8_t *dst, size_t size) const
Read the contents of a descriptor chain.
Definition: base.cc:168
uint64_t addr
Definition: virtio_ring.h:64
uint16_t next
Definition: virtio_ring.h:70
Bitfield< 9 > d
Definition: miscregs.hh:1375
void chainWrite(size_t offset, const uint8_t *src, size_t size)
Write to a descriptor chain.
Definition: base.cc:191
std::vector< VirtQueue * > _queues
List of virtual queues supported by this device.
Definition: base.hh:874
Header header
Ring buffer header in host byte order.
Definition: base.hh:532
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
Definition: serialize.cc:578
virtual void writeConfig(PacketPtr pkt, Addr cfgOffset)
Write to the configuration space of a device.
Definition: base.cc:414
VirtIO descriptor (chain) wrapper.
Definition: base.hh:136
Addr getAddress() const
Get the guest physical address of this queue.
Definition: base.hh:341
virtual void reset()
Driver-request device reset.
Definition: base.cc:361
void onNotify(QueueID index)
Driver is requesting service.
Definition: base.cc:372
Index _index
Index in virtqueue.
Definition: base.hh:302
virtual void readConfig(PacketPtr pkt, Addr cfgOffset)
Read from the configuration space of a device.
Definition: base.cc:408
VirtRing< VirtDescriptor::Index > avail
Ring of available (incoming) descriptors.
Definition: base.hh:547
const VirtQueue & getCurrentQueue() const
Convenience method to get the currently selected queue.
Definition: base.cc:445
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
virtual void onNotify()
Notify queue of pending events.
Definition: base.cc:314
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:245
VirtQueue * queue
Pointer to virtqueue owning this descriptor.
Definition: base.hh:299
size_t size() const
Retrieve the size of this descriptor.
Definition: base.hh:231
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:143
virtual void readBlob(Addr addr, uint8_t *p, int size) const
Read size bytes memory at address and store in p.
Definition: port_proxy.cc:45
FeatureBits guestFeatures
Feature set accepted by the guest.
Definition: base.hh:649
uint32_t getQueueAddress() const
Get the host physical address of the currently active queue.
Definition: base.cc:469
const uint16_t _size
Queue size in terms of number of descriptors.
Definition: base.hh:456
void updateChain()
Populate this descriptor chain with data from the guest.
Definition: base.cc:93
This object is a proxy for a structural port, to be used for debug accesses.
Definition: port_proxy.hh:84
VirtIODummyDevice(VirtIODummyDeviceParams *params)
Definition: base.cc:483
Bitfield< 9 > e
Definition: miscregs.hh:1376
VirtDescriptor * next() const
Get the pointer to the next descriptor in a chain.
Definition: base.cc:134
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
Definition: packet.hh:845
void registerQueue(VirtQueue &queue)
Register a new VirtQueue with the device model.
Definition: base.cc:477
int size()
Definition: pagetable.hh:146
uint16_t DeviceId
Device Type (sometimes known as subsystem ID)
Definition: base.hh:582
void read(size_t offset, uint8_t *dst, size_t size) const
Read the contents of a descriptor.
Definition: base.cc:144
const FeatureBits deviceFeatures
Feature set offered by the device.
Definition: base.hh:853
std::ostream CheckpointOut
Definition: serialize.hh:67
VirtIODeviceBase(Params *params, DeviceId id, size_t config_size, FeatureBits features)
Definition: base.cc:325
void setQueueAddress(uint32_t address)
Change the host physical address of the currently active queue.
Definition: base.cc:463
uint16_t Index
Descriptor index in virtqueue.
Definition: base.hh:140
virtual void writeBlob(Addr addr, const uint8_t *p, int size) const
Write size bytes from p to address.
Definition: port_proxy.cc:58
T vtoh_legacy(T v)
Convert legacy VirtIO endianness to host endianness.
Definition: base.hh:70
Bitfield< 18, 16 > len
Definition: miscregs.hh:1626
nomali_config_t cfg
Definition: gpu_nomali.cc:66
size_t chainSize() const
Retrieve the size of this descriptor chain.
Definition: base.cc:214
void update()
Populate this descriptor with data from the guest.
Definition: base.cc:74
VirtRing< struct vring_used_elem > used
Ring of used (outgoing) descriptors.
Definition: base.hh:549
void paramIn(CheckpointIn &cp, const string &name, ExtMachInst &machInst)
Definition: types.cc:71
uint16_t flags
Definition: virtio_ring.h:68
std::vector< T > ring
Elements in ring in host byte order.
Definition: base.hh:534
bool isOutgoing() const
Check if this is a write-only descriptor (outgoing data).
Definition: base.hh:250
static const unsigned ALIGN_SIZE
Definition: base.hh:437
unsigned getSize() const
Definition: packet.hh:649
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: base.cc:238
Base wrapper around a virtqueue.
Definition: base.hh:317
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: base.cc:351
uint16_t _last_avail
Offset of last consumed descriptor in the VirtQueue::avail ring.
Definition: base.hh:553
void readConfigBlob(PacketPtr pkt, Addr cfgOffset, const uint8_t *cfg)
Read configuration data from a device structure.
Definition: base.cc:420
vring_desc desc
Underlying descriptor.
Definition: base.hh:305
Abstract superclass for simulation objects.
Definition: sim_object.hh:94
uint32_t len
Definition: virtio_ring.h:66
const size_t configSize
Size of the device's configuration space.
Definition: base.hh:850
uint32_t FeatureBits
Definition: base.hh:574
uint16_t QueueID
Definition: base.hh:573
virtual void onNotifyDescriptor(VirtDescriptor *desc)
Notify queue of pending incoming descriptor.
Definition: base.hh:421
PortProxy * memProxy
Pointer to memory proxy.
Definition: base.hh:297

Generated on Fri Jun 9 2017 13:03:41 for gem5 by doxygen 1.8.6