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

Generated on Tue Jun 18 2024 16:24:01 for gem5 by doxygen 1.11.0