gem5  v19.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules 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 #include "sim/system.hh"
46 
48  VirtQueue &_queue, Index descIndex)
49  : memProxy(&_memProxy), queue(&_queue), byteOrder(bo), _index(descIndex),
50  desc{0, 0, 0, 0}
51 {
52 }
53 
55 {
56  *this = std::forward<VirtDescriptor>(other);
57 }
58 
60 {
61 }
62 
65 {
66  memProxy = std::move(rhs.memProxy);
67  queue = std::move(rhs.queue);
68  byteOrder = std::move(rhs.byteOrder);
69  _index = std::move(rhs._index);
70  desc = std::move(rhs.desc);
71 
72  return *this;
73 }
74 
75 void
77 {
78  const Addr vq_addr(queue->getAddress());
79  // Check if the queue has been initialized yet
80  if (vq_addr == 0)
81  return;
82 
83  assert(_index < queue->getSize());
84  const Addr desc_addr(vq_addr + sizeof(desc) * _index);
85  vring_desc guest_desc;
86  memProxy->readBlob(desc_addr, &guest_desc, sizeof(guest_desc));
87  desc = gtoh(guest_desc, byteOrder);
88  DPRINTF(VIO,
89  "VirtDescriptor(%i): Addr: 0x%x, Len: %i, Flags: 0x%x, "
90  "Next: 0x%x\n",
91  _index, desc.addr, desc.len, desc.flags, desc.next);
92 }
93 
94 void
96 {
97  VirtDescriptor *desc(this);
98  do {
99  desc->update();
100  } while ((desc = desc->next()) != NULL && desc != this);
101 
102  if (desc == this)
103  panic("Loop in descriptor chain!\n");
104 }
105 
106 void
108 {
109  if (!DTRACE(VIO))
110  return;
111 
112  DPRINTF(VIO, "Descriptor[%i]: "
113  "Addr: 0x%x, Len: %i, Flags: 0x%x, Next: 0x%x\n",
115 
116  if (isIncoming()) {
117  uint8_t data[desc.len];
118  read(0, data, desc.len);
119  DDUMP(VIO, data, desc.len);
120  }
121 }
122 
123 void
125 {
126  if (!DTRACE(VIO))
127  return;
128 
129  const VirtDescriptor *desc(this);
130  do {
131  desc->dump();
132  } while ((desc = desc->next()) != NULL);
133 }
134 
137 {
138  if (hasNext()) {
139  return queue->getDescriptor(desc.next);
140  } else {
141  return NULL;
142  }
143 }
144 
145 void
146 VirtDescriptor::read(size_t offset, uint8_t *dst, size_t size) const
147 {
148  DPRINTF(VIO, "VirtDescriptor(%p, 0x%x, %i)::read: offset: %i, dst: 0x%x, size: %i\n",
149  this, desc.addr, desc.len, offset, (long)dst, size);
150  assert(size <= desc.len - offset);
151  if (!isIncoming())
152  panic("Trying to read from outgoing buffer\n");
153 
154  memProxy->readBlob(desc.addr + offset, dst, size);
155 }
156 
157 void
158 VirtDescriptor::write(size_t offset, const uint8_t *src, size_t size)
159 {
160  DPRINTF(VIO, "VirtDescriptor(%p, 0x%x, %i)::write: offset: %i, src: 0x%x, size: %i\n",
161  this, desc.addr, desc.len, offset, (long)src, size);
162  assert(size <= desc.len - offset);
163  if (!isOutgoing())
164  panic("Trying to write to incoming buffer\n");
165 
166  memProxy->writeBlob(desc.addr + offset, src, size);
167 }
168 
169 void
170 VirtDescriptor::chainRead(size_t offset, uint8_t *dst, size_t size) const
171 {
172  const VirtDescriptor *desc(this);
173  const size_t full_size(size);
174  do {
175  if (offset < desc->size()) {
176  const size_t chunk_size(std::min(desc->size() - offset, size));
177  desc->read(offset, dst, chunk_size);
178  dst += chunk_size;
179  size -= chunk_size;
180  offset = 0;
181  } else {
182  offset -= desc->size();
183  }
184  } while ((desc = desc->next()) != NULL && desc->isIncoming() && size > 0);
185 
186  if (size != 0) {
187  panic("Failed to read %i bytes from chain of %i bytes @ offset %i\n",
188  full_size, chainSize(), offset);
189  }
190 }
191 
192 void
193 VirtDescriptor::chainWrite(size_t offset, const uint8_t *src, size_t size)
194 {
195  VirtDescriptor *desc(this);
196  const size_t full_size(size);
197  do {
198  if (offset < desc->size()) {
199  const size_t chunk_size(std::min(desc->size() - offset, size));
200  desc->write(offset, src, chunk_size);
201  src += chunk_size;
202  size -= chunk_size;
203  offset = 0;
204  } else {
205  offset -= desc->size();
206  }
207  } while ((desc = desc->next()) != NULL && size > 0);
208 
209  if (size != 0) {
210  panic("Failed to write %i bytes into chain of %i bytes @ offset %i\n",
211  full_size, chainSize(), offset);
212  }
213 }
214 
215 size_t
217 {
218  size_t size(0);
219  const VirtDescriptor *desc(this);
220  do {
221  size += desc->size();
222  } while ((desc = desc->next()) != NULL);
223 
224  return size;
225 }
226 
227 
228 
230  : byteOrder(bo), _size(size), _address(0), memProxy(proxy),
231  avail(proxy, bo, size), used(proxy, bo, size),
232  _last_avail(0)
233 {
234  descriptors.reserve(_size);
235  for (int i = 0; i < _size; ++i)
236  descriptors.emplace_back(proxy, bo, *this, i);
237 }
238 
239 void
241 {
244 }
245 
246 void
248 {
249  Addr addr_in;
250 
251  paramIn(cp, "_address", addr_in);
253 
254  // Use the address setter to ensure that the ring buffer addresses
255  // are updated as well.
256  setAddress(addr_in);
257 }
258 
259 void
261 {
262  const Addr addr_avail(address + _size * sizeof(struct vring_desc));
263  const Addr addr_avail_end(addr_avail + sizeof(struct vring_avail) +
264  _size * sizeof(uint16_t));
265  const Addr addr_used((addr_avail_end + sizeof(uint16_t) +
266  (ALIGN_SIZE - 1)) & ~(ALIGN_SIZE - 1));
267  _address = address;
268  avail.setAddress(addr_avail);
269  used.setAddress(addr_used);
270 }
271 
274 {
275  avail.read();
276  DPRINTF(VIO, "consumeDescriptor: _last_avail: %i, avail.idx: %i (->%i)\n",
277  _last_avail, avail.header.index,
278  avail.ring[_last_avail % used.ring.size()]);
279  if (_last_avail == avail.header.index)
280  return NULL;
281 
283  ++_last_avail;
284 
286  d->updateChain();
287 
288  return d;
289 }
290 
291 void
293 {
294  used.readHeader();
295  DPRINTF(VIO, "produceDescriptor: dscIdx: %i, len: %i, used.idx: %i\n",
296  desc->index(), len, used.header.index);
297 
298  struct vring_used_elem &e(used.ring[used.header.index % used.ring.size()]);
299  e.id = desc->index();
300  e.len = len;
301  used.header.index += 1;
302  used.write();
303 }
304 
305 void
307 {
308  if (!DTRACE(VIO))
309  return;
310 
311  for (const VirtDescriptor &d : descriptors)
312  d.dump();
313 }
314 
315 void
317 {
318  DPRINTF(VIO, "onNotify\n");
319 
320  // Consume all pending descriptors from the input queue.
321  VirtDescriptor *d;
322  while ((d = consumeDescriptor()) != NULL)
324 }
325 
326 
328  size_t config_size, FeatureBits features)
329  : SimObject(params),
330  guestFeatures(0),
331  byteOrder(params->system->getGuestByteOrder()),
332  deviceId(id), configSize(config_size), deviceFeatures(features),
333  _deviceStatus(0), _queueSelect(0),
334  transKick(NULL)
335 {
336 }
337 
338 
340 {
341 }
342 
343 void
345 {
349  for (QueueID i = 0; i < _queues.size(); ++i)
350  _queues[i]->serializeSection(cp, csprintf("_queues.%i", i));
351 }
352 
353 void
355 {
359  for (QueueID i = 0; i < _queues.size(); ++i)
360  _queues[i]->unserializeSection(cp, csprintf("_queues.%i", i));
361 }
362 
363 void
365 {
366  _queueSelect = 0;
367  guestFeatures = 0;
368  _deviceStatus = 0;
369 
370  for (QueueID i = 0; i < _queues.size(); ++i)
371  _queues[i]->setAddress(0);
372 }
373 
374 void
376 {
377  DPRINTF(VIO, "onNotify: idx: %i\n", idx);
378  if (idx >= _queues.size()) {
379  panic("Guest tried to notify queue (%i), but only %i "
380  "queues registered.\n",
381  idx, _queues.size());
382  }
383  _queues[idx]->onNotify();
384 }
385 
386 void
388 {
389  DPRINTF(VIO, "Setting guest features: 0x%x\n", features);
390  if (~deviceFeatures & features) {
391  panic("Guest tried to enable unsupported features:\n"
392  "Device features: 0x%x\n"
393  "Requested features: 0x%x\n",
394  deviceFeatures, features);
395  }
396  guestFeatures = features;
397 }
398 
399 
400 void
402 {
404  DPRINTF(VIO, "ACK: %i, DRIVER: %i, DRIVER_OK: %i, FAILED: %i\n",
405  status.acknowledge, status.driver, status.driver_ok, status.failed);
406  if (status == 0)
407  reset();
408 }
409 
410 void
412 {
413  panic("Unhandled device config read (offset: 0x%x).\n", cfgOffset);
414 }
415 
416 void
418 {
419  panic("Unhandled device config write (offset: 0x%x).\n", cfgOffset);
420 }
421 
422 void
423 VirtIODeviceBase::readConfigBlob(PacketPtr pkt, Addr cfgOffset, const uint8_t *cfg)
424 {
425  const unsigned size(pkt->getSize());
426 
427  if (cfgOffset + size > configSize)
428  panic("Config read out of bounds.\n");
429 
430  pkt->makeResponse();
431  pkt->setData(const_cast<uint8_t *>(cfg) + cfgOffset);
432 }
433 
434 void
435 VirtIODeviceBase::writeConfigBlob(PacketPtr pkt, Addr cfgOffset, uint8_t *cfg)
436 {
437  const unsigned size(pkt->getSize());
438 
439  if (cfgOffset + size > configSize)
440  panic("Config write out of bounds.\n");
441 
442  pkt->makeResponse();
443  pkt->writeData((uint8_t *)cfg + cfgOffset);
444 }
445 
446 
447 const VirtQueue &
449 {
450  if (_queueSelect >= _queues.size())
451  panic("Guest tried to access non-existing VirtQueue (%i).\n", _queueSelect);
452 
453  return *_queues[_queueSelect];
454 }
455 
456 VirtQueue &
458 {
459  if (_queueSelect >= _queues.size())
460  panic("Guest tried to access non-existing VirtQueue (%i).\n", _queueSelect);
461 
462  return *_queues[_queueSelect];
463 }
464 
465 void
467 {
469 }
470 
471 uint32_t
473 {
474  Addr address(getCurrentQueue().getAddress());
475  assert(!(address & ((1 >> VirtQueue::ALIGN_BITS) - 1)));
476  return address >> VirtQueue::ALIGN_BITS;
477 }
478 
479 void
481 {
482  _queues.push_back(&queue);
483 }
484 
485 
487  : VirtIODeviceBase(params, ID_INVALID, 0, 0)
488 {
489 }
490 
492 VirtIODummyDeviceParams::create()
493 {
494  return new VirtIODummyDevice(this);
495 }
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:167
#define DPRINTF(x,...)
Definition: trace.hh:229
Base class for all VirtIO-based devices.
Definition: base.hh:560
void write(size_t offset, const uint8_t *src, size_t size)
Write to the contents of a descriptor.
Definition: base.cc:158
VirtDescriptor * next() const
Get the pointer to the next descriptor in a chain.
Definition: base.cc:136
VirtDescriptor & operator=(VirtDescriptor &&rhs) noexcept
Definition: base.cc:64
Bitfield< 30, 0 > index
void setAddress(Addr address)
Set the base address of this queue.
Definition: base.cc:260
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: base.cc:247
void serializeSection(CheckpointOut &cp, const char *name) const
Serialize an object into a new section.
Definition: serialize.cc:176
T gtoh(T value, ByteOrder guest_byte_order)
Definition: byteswap.hh:166
Bitfield< 7 > i
~VirtDescriptor() noexcept
Definition: base.cc:59
SimObjectParams Params
Definition: sim_object.hh:113
void unserializeSection(CheckpointIn &cp, const char *name)
Unserialize an a child object.
Definition: serialize.cc:183
static const Addr ALIGN_SIZE
Definition: base.hh:413
#define DDUMP(x, data, count)
Definition: trace.hh:228
void setGuestFeatures(FeatureBits features)
Set feature bits accepted by the guest driver.
Definition: base.cc:387
VirtDescriptor * getDescriptor(VirtDescriptor::Index index)
Get a pointer to a specific descriptor in the queue.
Definition: base.hh:335
void dumpChain() const
Dump the contents of a descriptor chain starting at this descriptor.
Definition: base.cc:124
void setAddress(Addr addr)
Set the base address of the VirtIO ring buffer.
Definition: base.hh:470
Bitfield< 23, 0 > offset
Definition: types.hh:154
Definition: cprintf.cc:42
void setDeviceStatus(DeviceStatus status)
Update device status and optionally reset device.
Definition: base.cc:401
virtual ~VirtIODeviceBase()
Definition: base.cc:339
size_t size() const
Retrieve the size of this descriptor.
Definition: base.hh:204
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: base.cc:344
void readHeader()
Update the ring buffer header with data from the guest.
Definition: base.hh:474
VirtDescriptor * consumeDescriptor()
Get an incoming descriptor chain from the queue.
Definition: base.cc:273
Bitfield< 5, 0 > status
void dump() const
Dump the contents of a queue.
Definition: base.cc:306
void produceDescriptor(VirtDescriptor *desc, uint32_t len)
Send a descriptor chain to the guest.
Definition: base.cc:292
void chainRead(size_t offset, uint8_t *dst, size_t size) const
Read the contents of a descriptor chain.
Definition: base.cc:170
unsigned getSize() const
Definition: packet.hh:736
Addr _address
Base address of the queue.
Definition: base.hh:437
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:645
ByteOrder byteOrder
The byte order the descriptor is stored in.
Definition: base.hh:275
void writeConfigBlob(PacketPtr pkt, Addr cfgOffset, uint8_t *cfg)
Write configuration data to a device structure.
Definition: base.cc:435
std::string csprintf(const char *format, const Args &...args)
Definition: cprintf.hh:162
DeviceStatus _deviceStatus
Status of the device.
Definition: base.hh:863
#define DTRACE(x)
Definition: trace.hh:227
ByteOrder byteOrder(ThreadContext *tc)
Definition: utility.hh:374
void setData(const uint8_t *p)
Copy data into the packet from the provided pointer.
Definition: packet.hh:1158
void writeBlob(Addr addr, const void *p, int size) const
Same as tryWriteBlob, but insists on success.
Definition: port_proxy.hh:189
bool isIncoming() const
Check if this is a read-only descriptor (incoming data).
Definition: base.hh:221
const Params * params() const
Definition: sim_object.hh:114
void read(size_t offset, uint8_t *dst, size_t size) const
Read the contents of a descriptor.
Definition: base.cc:146
size_t chainSize() const
Retrieve the size of this descriptor chain.
Definition: base.cc:216
QueueID _queueSelect
Queue select register (set by guest)
Definition: base.hh:866
std::vector< VirtDescriptor > descriptors
Vector of pre-created descriptors indexed by their index into the queue.
Definition: base.hh:547
uint64_t addr
Definition: virtio_ring.h:64
uint16_t next
Definition: virtio_ring.h:70
ByteOrder
Definition: types.hh:247
Bitfield< 9 > d
void chainWrite(size_t offset, const uint8_t *src, size_t size)
Write to a descriptor chain.
Definition: base.cc:193
std::vector< VirtQueue * > _queues
List of virtual queues supported by this device.
Definition: base.hh:869
Header header
Ring buffer header in host byte order.
Definition: base.hh:520
Bitfield< 18, 16 > len
virtual void writeConfig(PacketPtr pkt, Addr cfgOffset)
Write to the configuration space of a device.
Definition: base.cc:417
VirtIO descriptor (chain) wrapper.
Definition: base.hh:108
void writeData(uint8_t *p) const
Copy data from the packet to the memory at the provided pointer.
Definition: packet.hh:1187
virtual void reset()
Driver-request device reset.
Definition: base.cc:364
void dump() const
Dump the contents of a descriptor.
Definition: base.cc:107
void onNotify(QueueID index)
Driver is requesting service.
Definition: base.cc:375
Index _index
Index in virtqueue.
Definition: base.hh:278
virtual void readConfig(PacketPtr pkt, Addr cfgOffset)
Read from the configuration space of a device.
Definition: base.cc:411
VirtRing< VirtDescriptor::Index > avail
Ring of available (incoming) descriptors.
Definition: base.hh:537
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:316
Index index() const
Get the descriptor&#39;s index into the virtqueue.
Definition: base.hh:135
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
Definition: packet.hh:255
Bitfield< 15 > system
Definition: misc.hh:999
void readBlob(Addr addr, void *p, int size) const
Higher level interfaces based on the above.
Definition: port_proxy.hh:179
VirtQueue * queue
Pointer to virtqueue owning this descriptor.
Definition: base.hh:272
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:643
FeatureBits guestFeatures
Feature set accepted by the guest.
Definition: base.hh:639
const uint16_t _size
Queue size in terms of number of descriptors.
Definition: base.hh:435
void updateChain()
Populate this descriptor chain with data from the guest.
Definition: base.cc:95
This object is a proxy for a port or other object which implements the functional response protocol...
Definition: port_proxy.hh:82
VirtIODummyDevice(VirtIODummyDeviceParams *params)
Definition: base.cc:486
Bitfield< 9 > e
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:937
void registerQueue(VirtQueue &queue)
Register a new VirtQueue with the device model.
Definition: base.cc:480
Bitfield< 25, 21 > bo
Definition: types.hh:64
uint16_t DeviceId
Device Type (sometimes known as subsystem ID)
Definition: base.hh:572
const VirtQueue & getCurrentQueue() const
Convenience method to get the currently selected queue.
Definition: base.cc:448
const FeatureBits deviceFeatures
Feature set offered by the device.
Definition: base.hh:848
Addr getAddress() const
Get the guest physical address of this queue.
Definition: base.hh:317
std::ostream CheckpointOut
Definition: serialize.hh:68
VirtIODeviceBase(Params *params, DeviceId id, size_t config_size, FeatureBits features)
Definition: base.cc:327
bool isOutgoing() const
Check if this is a write-only descriptor (outgoing data).
Definition: base.hh:223
void setQueueAddress(uint32_t address)
Change the host physical address of the currently active queue.
Definition: base.cc:466
uint16_t Index
Descriptor index in virtqueue.
Definition: base.hh:112
uint32_t getQueueAddress() const
Get the host physical address of the currently active queue.
Definition: base.cc:472
void update()
Populate this descriptor with data from the guest.
Definition: base.cc:76
VirtRing< struct vring_used_elem > used
Ring of used (outgoing) descriptors.
Definition: base.hh:539
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:522
ByteOrder byteOrder
Byte order in this queue.
Definition: base.hh:429
static const Addr ALIGN_BITS
Page size used by VirtIO. It&#39;s hard-coded to 4096 bytes in the spec for historical reasons...
Definition: base.hh:412
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: base.cc:240
Base wrapper around a virtqueue.
Definition: base.hh:293
bool hasNext() const
Is this descriptor chained to another descriptor?
Definition: base.hh:211
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: base.cc:354
uint16_t _last_avail
Offset of last consumed descriptor in the VirtQueue::avail ring.
Definition: base.hh:543
const char data[]
void readConfigBlob(PacketPtr pkt, Addr cfgOffset, const uint8_t *cfg)
Read configuration data from a device structure.
Definition: base.cc:423
vring_desc desc
Underlying descriptor.
Definition: base.hh:281
Abstract superclass for simulation objects.
Definition: sim_object.hh:96
uint32_t len
Definition: virtio_ring.h:66
const size_t configSize
Size of the device&#39;s configuration space.
Definition: base.hh:845
uint32_t FeatureBits
Definition: base.hh:564
uint16_t QueueID
Definition: base.hh:563
virtual void onNotifyDescriptor(VirtDescriptor *desc)
Notify queue of pending incoming descriptor.
Definition: base.hh:397
PortProxy * memProxy
Pointer to memory proxy.
Definition: base.hh:270

Generated on Fri Feb 28 2020 16:26:59 for gem5 by doxygen 1.8.13