0443fb498d6f38cb063f2e3f02841928bacd317c
2 * Copyright (c) 2014, 2016 ARM Limited
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.
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.
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.
38 #include "dev/virtio/base.hh"
40 #include "base/trace.hh"
41 #include "debug/VIO.hh"
42 #include "params/VirtIODeviceBase.hh"
43 #include "params/VirtIODummyDevice.hh"
45 VirtDescriptor::VirtDescriptor(PortProxy
&_memProxy
, ByteOrder bo
,
46 VirtQueue
&_queue
, Index descIndex
)
47 : memProxy(&_memProxy
), queue(&_queue
), byteOrder(bo
), _index(descIndex
),
52 VirtDescriptor::VirtDescriptor(VirtDescriptor
&&other
) noexcept
54 *this = std::forward
<VirtDescriptor
>(other
);
57 VirtDescriptor::~VirtDescriptor() noexcept
62 VirtDescriptor::operator=(VirtDescriptor
&&rhs
) noexcept
64 memProxy
= std::move(rhs
.memProxy
);
65 queue
= std::move(rhs
.queue
);
66 byteOrder
= std::move(rhs
.byteOrder
);
67 _index
= std::move(rhs
._index
);
68 desc
= std::move(rhs
.desc
);
74 VirtDescriptor::update()
76 const Addr
vq_addr(queue
->getAddress());
77 // Check if the queue has been initialized yet
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
, &guest_desc
, sizeof(guest_desc
));
85 desc
= gtoh(guest_desc
, byteOrder
);
87 "VirtDescriptor(%i): Addr: 0x%x, Len: %i, Flags: 0x%x, "
89 _index
, desc
.addr
, desc
.len
, desc
.flags
, desc
.next
);
93 VirtDescriptor::updateChain()
95 VirtDescriptor
*desc(this);
98 } while ((desc
= desc
->next()) != NULL
&& desc
!= this);
101 panic("Loop in descriptor chain!\n");
105 VirtDescriptor::dump() const
110 DPRINTF(VIO
, "Descriptor[%i]: "
111 "Addr: 0x%x, Len: %i, Flags: 0x%x, Next: 0x%x\n",
112 _index
, desc
.addr
, desc
.len
, desc
.flags
, desc
.next
);
115 uint8_t data
[desc
.len
];
116 read(0, data
, desc
.len
);
117 DDUMP(VIO
, data
, desc
.len
);
122 VirtDescriptor::dumpChain() const
127 const VirtDescriptor
*desc(this);
130 } while ((desc
= desc
->next()) != NULL
);
134 VirtDescriptor::next() const
137 return queue
->getDescriptor(desc
.next
);
144 VirtDescriptor::read(size_t offset
, uint8_t *dst
, size_t size
) const
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
);
150 panic("Trying to read from outgoing buffer\n");
152 memProxy
->readBlob(desc
.addr
+ offset
, dst
, size
);
156 VirtDescriptor::write(size_t offset
, const uint8_t *src
, size_t size
)
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
);
162 panic("Trying to write to incoming buffer\n");
164 memProxy
->writeBlob(desc
.addr
+ offset
, src
, size
);
168 VirtDescriptor::chainRead(size_t offset
, uint8_t *dst
, size_t size
) const
170 const VirtDescriptor
*desc(this);
171 const size_t full_size(size
);
173 if (offset
< desc
->size()) {
174 const size_t chunk_size(std::min(desc
->size() - offset
, size
));
175 desc
->read(offset
, dst
, chunk_size
);
180 offset
-= desc
->size();
182 } while ((desc
= desc
->next()) != NULL
&& desc
->isIncoming() && size
> 0);
185 panic("Failed to read %i bytes from chain of %i bytes @ offset %i\n",
186 full_size
, chainSize(), offset
);
191 VirtDescriptor::chainWrite(size_t offset
, const uint8_t *src
, size_t size
)
193 VirtDescriptor
*desc(this);
194 const size_t full_size(size
);
196 if (offset
< desc
->size()) {
197 const size_t chunk_size(std::min(desc
->size() - offset
, size
));
198 desc
->write(offset
, src
, chunk_size
);
203 offset
-= desc
->size();
205 } while ((desc
= desc
->next()) != NULL
&& size
> 0);
208 panic("Failed to write %i bytes into chain of %i bytes @ offset %i\n",
209 full_size
, chainSize(), offset
);
214 VirtDescriptor::chainSize() const
217 const VirtDescriptor
*desc(this);
219 size
+= desc
->size();
220 } while ((desc
= desc
->next()) != NULL
);
227 VirtQueue::VirtQueue(PortProxy
&proxy
, ByteOrder bo
, uint16_t size
)
228 : byteOrder(bo
), _size(size
), _address(0), memProxy(proxy
),
229 avail(proxy
, bo
, size
), used(proxy
, bo
, size
),
232 descriptors
.reserve(_size
);
233 for (int i
= 0; i
< _size
; ++i
)
234 descriptors
.emplace_back(proxy
, bo
, *this, i
);
238 VirtQueue::serialize(CheckpointOut
&cp
) const
240 SERIALIZE_SCALAR(_address
);
241 SERIALIZE_SCALAR(_last_avail
);
245 VirtQueue::unserialize(CheckpointIn
&cp
)
249 paramIn(cp
, "_address", addr_in
);
250 UNSERIALIZE_SCALAR(_last_avail
);
252 // Use the address setter to ensure that the ring buffer addresses
253 // are updated as well.
258 VirtQueue::setAddress(Addr address
)
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));
266 avail
.setAddress(addr_avail
);
267 used
.setAddress(addr_used
);
271 VirtQueue::consumeDescriptor()
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
)
280 VirtDescriptor::Index
index(avail
.ring
[_last_avail
% used
.ring
.size()]);
283 VirtDescriptor
*d(&descriptors
[index
]);
290 VirtQueue::produceDescriptor(VirtDescriptor
*desc
, uint32_t len
)
293 DPRINTF(VIO
, "produceDescriptor: dscIdx: %i, len: %i, used.idx: %i\n",
294 desc
->index(), len
, used
.header
.index
);
296 struct vring_used_elem
&e(used
.ring
[used
.header
.index
% used
.ring
.size()]);
297 e
.id
= desc
->index();
299 used
.header
.index
+= 1;
304 VirtQueue::dump() const
309 for (const VirtDescriptor
&d
: descriptors
)
314 VirtQueue::onNotify()
316 DPRINTF(VIO
, "onNotify\n");
318 // Consume all pending descriptors from the input queue.
320 while ((d
= consumeDescriptor()) != NULL
)
321 onNotifyDescriptor(d
);
325 VirtIODeviceBase::VirtIODeviceBase(const Params
¶ms
, DeviceId id
,
326 size_t config_size
, FeatureBits features
)
329 byteOrder(params
.byte_order
),
330 deviceId(id
), configSize(config_size
), deviceFeatures(features
),
331 _deviceStatus(0), _queueSelect(0)
336 VirtIODeviceBase::~VirtIODeviceBase()
341 VirtIODeviceBase::serialize(CheckpointOut
&cp
) const
343 SERIALIZE_SCALAR(guestFeatures
);
344 SERIALIZE_SCALAR(_deviceStatus
);
345 SERIALIZE_SCALAR(_queueSelect
);
346 for (QueueID i
= 0; i
< _queues
.size(); ++i
)
347 _queues
[i
]->serializeSection(cp
, csprintf("_queues.%i", i
));
351 VirtIODeviceBase::unserialize(CheckpointIn
&cp
)
353 UNSERIALIZE_SCALAR(guestFeatures
);
354 UNSERIALIZE_SCALAR(_deviceStatus
);
355 UNSERIALIZE_SCALAR(_queueSelect
);
356 for (QueueID i
= 0; i
< _queues
.size(); ++i
)
357 _queues
[i
]->unserializeSection(cp
, csprintf("_queues.%i", i
));
361 VirtIODeviceBase::reset()
367 for (QueueID i
= 0; i
< _queues
.size(); ++i
)
368 _queues
[i
]->setAddress(0);
372 VirtIODeviceBase::onNotify(QueueID idx
)
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());
380 _queues
[idx
]->onNotify();
384 VirtIODeviceBase::setGuestFeatures(FeatureBits features
)
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
);
393 guestFeatures
= features
;
398 VirtIODeviceBase::setDeviceStatus(DeviceStatus status
)
400 _deviceStatus
= status
;
401 DPRINTF(VIO
, "ACK: %i, DRIVER: %i, DRIVER_OK: %i, FAILED: %i\n",
402 status
.acknowledge
, status
.driver
, status
.driver_ok
, status
.failed
);
408 VirtIODeviceBase::readConfig(PacketPtr pkt
, Addr cfgOffset
)
410 panic("Unhandled device config read (offset: 0x%x).\n", cfgOffset
);
414 VirtIODeviceBase::writeConfig(PacketPtr pkt
, Addr cfgOffset
)
416 panic("Unhandled device config write (offset: 0x%x).\n", cfgOffset
);
420 VirtIODeviceBase::readConfigBlob(PacketPtr pkt
, Addr cfgOffset
, const uint8_t *cfg
)
422 const unsigned size(pkt
->getSize());
424 if (cfgOffset
+ size
> configSize
)
425 panic("Config read out of bounds.\n");
428 pkt
->setData(const_cast<uint8_t *>(cfg
) + cfgOffset
);
432 VirtIODeviceBase::writeConfigBlob(PacketPtr pkt
, Addr cfgOffset
, uint8_t *cfg
)
434 const unsigned size(pkt
->getSize());
436 if (cfgOffset
+ size
> configSize
)
437 panic("Config write out of bounds.\n");
440 pkt
->writeData((uint8_t *)cfg
+ cfgOffset
);
445 VirtIODeviceBase::getCurrentQueue() const
447 if (_queueSelect
>= _queues
.size())
448 panic("Guest tried to access non-existing VirtQueue (%i).\n", _queueSelect
);
450 return *_queues
[_queueSelect
];
454 VirtIODeviceBase::getCurrentQueue()
456 if (_queueSelect
>= _queues
.size())
457 panic("Guest tried to access non-existing VirtQueue (%i).\n", _queueSelect
);
459 return *_queues
[_queueSelect
];
463 VirtIODeviceBase::setQueueAddress(uint32_t address
)
465 getCurrentQueue().setAddress(address
* VirtQueue::ALIGN_SIZE
);
469 VirtIODeviceBase::getQueueAddress() const
471 Addr
address(getCurrentQueue().getAddress());
472 assert(!(address
& ((1 >> VirtQueue::ALIGN_BITS
) - 1)));
473 return address
>> VirtQueue::ALIGN_BITS
;
477 VirtIODeviceBase::registerQueue(VirtQueue
&queue
)
479 _queues
.push_back(&queue
);
483 VirtIODummyDevice::VirtIODummyDevice(const VirtIODummyDeviceParams
¶ms
)
484 : VirtIODeviceBase(params
, ID_INVALID
, 0, 0)
489 VirtIODummyDeviceParams::create() const
491 return new VirtIODummyDevice(*this);