base.hh (10559:62f5f7363197) base.hh (10905:a6ca6831e775)
1/*
2 * Copyright (c) 2014 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#ifndef __DEV_VIRTIO_BASE_HH__
41#define __DEV_VIRTIO_BASE_HH__
42
43#include "arch/isa_traits.hh"
44#include "base/bitunion.hh"
45#include "base/callback.hh"
46#include "dev/virtio/virtio_ring.h"
47#include "mem/port_proxy.hh"
48#include "sim/sim_object.hh"
49
50struct VirtIODeviceBaseParams;
51class VirtQueue;
52
53/** @{
54 * @name VirtIO endian conversion helpers
55 *
56 * VirtIO prior to version 1.0 (legacy versions) normally send values
57 * to the host in the guest systems native byte order. This is going
58 * to change in version 1.0 which mandates little endian. We currently
59 * only support the legacy version of VirtIO (the new and shiny
60 * standard is still in a draft state and not implemented by the
61 * kernel). Once we support the new standard, we should negotiate the
62 * VirtIO version with the guest and automatically use the right type
63 * of byte swapping.
64 */
65
66/** Convert legacy VirtIO endianness to host endianness. */
67template <typename T> inline T
68vtoh_legacy(T v) {
69 return TheISA::gtoh(v);
70}
71
72/** Convert host endianness to legacy VirtIO endianness. */
73template <typename T> inline T
74htov_legacy(T v) {
75 return TheISA::htog(v);
76}
77
78
79template <> inline vring_used_elem
80vtoh_legacy(vring_used_elem v) {
81 v.id = vtoh_legacy(v.id);
82 v.len = vtoh_legacy(v.len);
83 return v;
84}
85
86template <> inline vring_used_elem
87htov_legacy(vring_used_elem v) {
88 v.id = htov_legacy(v.id);
89 v.len = htov_legacy(v.len);
90 return v;
91}
92
93template <> inline vring_desc
94vtoh_legacy(vring_desc v) {
95 v.addr = vtoh_legacy(v.addr);
96 v.len = vtoh_legacy(v.len);
97 v.flags = vtoh_legacy(v.flags);
98 v.next = vtoh_legacy(v.next);
99 return v;
100}
101
102template <> inline vring_desc
103htov_legacy(vring_desc v) {
104 v.addr = htov_legacy(v.addr);
105 v.len = htov_legacy(v.len);
106 v.flags = htov_legacy(v.flags);
107 v.next = htov_legacy(v.next);
108 return v;
109}
110
111/** @} */
112
113/**
114 * VirtIO descriptor (chain) wrapper
115 *
116 * Communication in VirtIO takes place by sending and receiving chains
117 * of so called descriptors using device queues. The queue is
118 * responsible for sending a descriptor chain from the guest to the
119 * host and later sending it back to the guest. The descriptor chain
120 * itself can be thought of as a linked list of buffers (descriptors)
121 * that are read only (isIncoming() is true) or write only
122 * (isOutgoing() is true). A single chain may contain any mix of input
123 * and output buffers.
124 *
125 * The descriptor wrapper is normally <i>only</i> instantiated by the
126 * virtqueue wrapper (VirtQueue) and should never be instantiated in
127 * device models. The VirtQueue also ensures that the descriptor
128 * wrapper is re-populated with new data from the guest by calling
129 * updateChain() whenever a new descriptor chain is passed to the host
130 * (VirtQueue::consumeDescriptor()). The updateChain() method
131 * automatically does some sanity checks on the descriptor chain to
132 * detect loops.
133 */
134class VirtDescriptor
135{
136 public:
137 /** Descriptor index in virtqueue */
138 typedef uint16_t Index;
139
140 /** @{
141 * @name VirtIO Descriptor <-> Queue Interface
142 */
143 /**
144 * Create a descriptor wrapper.
145 *
146 * @param memProxy Proxy to the guest physical memory.
147 * @param queue Queue owning this descriptor.
148 * @param index Index within the queue.
149 */
150 VirtDescriptor(PortProxy &memProxy, VirtQueue &queue, Index index);
151 // WORKAROUND: The noexcept declaration works around a bug where
152 // gcc 4.7 tries to call the wrong constructor when emplacing
153 // something into a vector.
154 VirtDescriptor(VirtDescriptor &&other) noexcept;
155 ~VirtDescriptor() noexcept;
156
157 VirtDescriptor &operator=(VirtDescriptor &&rhs) noexcept;
158
159 /** Get the descriptor's index into the virtqueue. */
160 Index index() const { return _index; }
161
162 /** Populate this descriptor with data from the guest. */
163 void update();
164
165 /** Populate this descriptor chain with data from the guest. */
166 void updateChain();
167 /** @} */
168
169 /** @{
170 * @name Debug interfaces
171 */
172 /**
173 * Dump the contents of a descriptor
174 */
175 void dump() const;
176 /**
177 * Dump the contents of a descriptor chain starting at this
178 * descriptor.
179 */
180 void dumpChain() const;
181 /** @} */
182
183
184 /** @{
185 * @name Device Model Interfaces
186 */
187 /**
188 * Read the contents of a descriptor.
189 *
190 * This method copies the contents of a descriptor into a buffer
191 * within gem5. Devices should typically use chainRead() instead
192 * as it automatically follows the descriptor chain to read the
193 * desired number of bytes.
194 *
195 * @see chainRead
196 *
197 * @param offset Offset into the descriptor.
198 * @param dst Destination buffer.
199 * @param size Amount of data to read (in bytes).
200 */
201 void read(size_t offset, uint8_t *dst, size_t size) const;
202 /**
203 * Write to the contents of a descriptor.
204 *
205 * This method copies the contents of a descriptor into a buffer
206 * within gem5. Devices should typically use chainWrite() instead
207 * as it automatically follows the descriptor chain to read the
208 * desired number of bytes.
209 *
210 * @see chainWrite
211 *
212 * @param offset Offset into the descriptor.
213 * @param src Source buffer.
214 * @param size Amount of data to read (in bytes).
215 */
216 void write(size_t offset, const uint8_t *src, size_t size);
217 /**
218 * Retrieve the size of this descriptor.
219 *
220 * This method gets the size of a single descriptor. For incoming
221 * data, it corresponds to the amount of data that can be read
222 * from the descriptor. For outgoing data, it corresponds to the
223 * amount of data that can be written to it.
224 *
225 * @see chainSize
226 *
227 * @return Size of descriptor in bytes.
228 */
229 size_t size() const { return desc.len; }
230
231 /**
232 * Is this descriptor chained to another descriptor?
233 *
234 * @return true if there is a next pointer, false otherwise.
235 */
236 bool hasNext() const { return desc.flags & VRING_DESC_F_NEXT; }
237 /**
238 * Get the pointer to the next descriptor in a chain.
239 *
240 * @return Pointer to the next descriptor or NULL if this is the
241 * last element in a chain.
242 */
243 VirtDescriptor *next() const;
244
245 /** Check if this is a read-only descriptor (incoming data). */
246 bool isIncoming() const { return !isOutgoing(); }
247 /** Check if this is a write-only descriptor (outgoing data). */
248 bool isOutgoing() const { return desc.flags & VRING_DESC_F_WRITE; }
249
250
251 /**
252 * Read the contents of a descriptor chain.
253 *
254 * This method reads the specified number of bytes from a
255 * descriptor chain starting at the this descriptor plus an offset
256 * in bytes. The method automatically follows the links in the
257 * descriptor chain.
258 *
259 * @param offset Offset into the chain (in bytes).
260 * @param dst Pointer to destination buffer.
261 * @param size Size (in bytes).
262 */
263 void chainRead(size_t offset, uint8_t *dst, size_t size) const;
264 /**
265 * Write to a descriptor chain.
266 *
267 * This method writes the specified number of bytes to a
268 * descriptor chain starting at the this descriptor plus an offset
269 * in bytes. The method automatically follows the links in the
270 * descriptor chain.
271 *
272 * @param offset Offset into the chain (in bytes).
273 * @param src Pointer to source buffer.
274 * @param size Size (in bytes).
275 */
276 void chainWrite(size_t offset, const uint8_t *src, size_t size);
277 /**
278 * Retrieve the size of this descriptor chain.
279 *
280 * This method gets the size of a descriptor chain starting at
281 * this descriptor.
282 *
283 * @return Size of descriptor chain in bytes.
284 */
285 size_t chainSize() const;
286 /** @} */
287
288 private:
289 // Remove default constructor
290 VirtDescriptor();
291 // Prevent copying
292 VirtDescriptor(const VirtDescriptor &other);
293
294 /** Pointer to memory proxy */
295 PortProxy *memProxy;
296 /** Pointer to virtqueue owning this descriptor */
297 VirtQueue *queue;
298
299 /** Index in virtqueue */
300 Index _index;
301
302 /** Underlying descriptor */
303 vring_desc desc;
304};
305
306/**
307 * Base wrapper around a virtqueue.
308 *
309 * VirtIO device models typically need to extend this class to
310 * implement their own device queues.
311 *
312 * @note Queues must be registered with
313 * VirtIODeviceBase::registerQueue() to be active.
314 */
1/*
2 * Copyright (c) 2014 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#ifndef __DEV_VIRTIO_BASE_HH__
41#define __DEV_VIRTIO_BASE_HH__
42
43#include "arch/isa_traits.hh"
44#include "base/bitunion.hh"
45#include "base/callback.hh"
46#include "dev/virtio/virtio_ring.h"
47#include "mem/port_proxy.hh"
48#include "sim/sim_object.hh"
49
50struct VirtIODeviceBaseParams;
51class VirtQueue;
52
53/** @{
54 * @name VirtIO endian conversion helpers
55 *
56 * VirtIO prior to version 1.0 (legacy versions) normally send values
57 * to the host in the guest systems native byte order. This is going
58 * to change in version 1.0 which mandates little endian. We currently
59 * only support the legacy version of VirtIO (the new and shiny
60 * standard is still in a draft state and not implemented by the
61 * kernel). Once we support the new standard, we should negotiate the
62 * VirtIO version with the guest and automatically use the right type
63 * of byte swapping.
64 */
65
66/** Convert legacy VirtIO endianness to host endianness. */
67template <typename T> inline T
68vtoh_legacy(T v) {
69 return TheISA::gtoh(v);
70}
71
72/** Convert host endianness to legacy VirtIO endianness. */
73template <typename T> inline T
74htov_legacy(T v) {
75 return TheISA::htog(v);
76}
77
78
79template <> inline vring_used_elem
80vtoh_legacy(vring_used_elem v) {
81 v.id = vtoh_legacy(v.id);
82 v.len = vtoh_legacy(v.len);
83 return v;
84}
85
86template <> inline vring_used_elem
87htov_legacy(vring_used_elem v) {
88 v.id = htov_legacy(v.id);
89 v.len = htov_legacy(v.len);
90 return v;
91}
92
93template <> inline vring_desc
94vtoh_legacy(vring_desc v) {
95 v.addr = vtoh_legacy(v.addr);
96 v.len = vtoh_legacy(v.len);
97 v.flags = vtoh_legacy(v.flags);
98 v.next = vtoh_legacy(v.next);
99 return v;
100}
101
102template <> inline vring_desc
103htov_legacy(vring_desc v) {
104 v.addr = htov_legacy(v.addr);
105 v.len = htov_legacy(v.len);
106 v.flags = htov_legacy(v.flags);
107 v.next = htov_legacy(v.next);
108 return v;
109}
110
111/** @} */
112
113/**
114 * VirtIO descriptor (chain) wrapper
115 *
116 * Communication in VirtIO takes place by sending and receiving chains
117 * of so called descriptors using device queues. The queue is
118 * responsible for sending a descriptor chain from the guest to the
119 * host and later sending it back to the guest. The descriptor chain
120 * itself can be thought of as a linked list of buffers (descriptors)
121 * that are read only (isIncoming() is true) or write only
122 * (isOutgoing() is true). A single chain may contain any mix of input
123 * and output buffers.
124 *
125 * The descriptor wrapper is normally <i>only</i> instantiated by the
126 * virtqueue wrapper (VirtQueue) and should never be instantiated in
127 * device models. The VirtQueue also ensures that the descriptor
128 * wrapper is re-populated with new data from the guest by calling
129 * updateChain() whenever a new descriptor chain is passed to the host
130 * (VirtQueue::consumeDescriptor()). The updateChain() method
131 * automatically does some sanity checks on the descriptor chain to
132 * detect loops.
133 */
134class VirtDescriptor
135{
136 public:
137 /** Descriptor index in virtqueue */
138 typedef uint16_t Index;
139
140 /** @{
141 * @name VirtIO Descriptor <-> Queue Interface
142 */
143 /**
144 * Create a descriptor wrapper.
145 *
146 * @param memProxy Proxy to the guest physical memory.
147 * @param queue Queue owning this descriptor.
148 * @param index Index within the queue.
149 */
150 VirtDescriptor(PortProxy &memProxy, VirtQueue &queue, Index index);
151 // WORKAROUND: The noexcept declaration works around a bug where
152 // gcc 4.7 tries to call the wrong constructor when emplacing
153 // something into a vector.
154 VirtDescriptor(VirtDescriptor &&other) noexcept;
155 ~VirtDescriptor() noexcept;
156
157 VirtDescriptor &operator=(VirtDescriptor &&rhs) noexcept;
158
159 /** Get the descriptor's index into the virtqueue. */
160 Index index() const { return _index; }
161
162 /** Populate this descriptor with data from the guest. */
163 void update();
164
165 /** Populate this descriptor chain with data from the guest. */
166 void updateChain();
167 /** @} */
168
169 /** @{
170 * @name Debug interfaces
171 */
172 /**
173 * Dump the contents of a descriptor
174 */
175 void dump() const;
176 /**
177 * Dump the contents of a descriptor chain starting at this
178 * descriptor.
179 */
180 void dumpChain() const;
181 /** @} */
182
183
184 /** @{
185 * @name Device Model Interfaces
186 */
187 /**
188 * Read the contents of a descriptor.
189 *
190 * This method copies the contents of a descriptor into a buffer
191 * within gem5. Devices should typically use chainRead() instead
192 * as it automatically follows the descriptor chain to read the
193 * desired number of bytes.
194 *
195 * @see chainRead
196 *
197 * @param offset Offset into the descriptor.
198 * @param dst Destination buffer.
199 * @param size Amount of data to read (in bytes).
200 */
201 void read(size_t offset, uint8_t *dst, size_t size) const;
202 /**
203 * Write to the contents of a descriptor.
204 *
205 * This method copies the contents of a descriptor into a buffer
206 * within gem5. Devices should typically use chainWrite() instead
207 * as it automatically follows the descriptor chain to read the
208 * desired number of bytes.
209 *
210 * @see chainWrite
211 *
212 * @param offset Offset into the descriptor.
213 * @param src Source buffer.
214 * @param size Amount of data to read (in bytes).
215 */
216 void write(size_t offset, const uint8_t *src, size_t size);
217 /**
218 * Retrieve the size of this descriptor.
219 *
220 * This method gets the size of a single descriptor. For incoming
221 * data, it corresponds to the amount of data that can be read
222 * from the descriptor. For outgoing data, it corresponds to the
223 * amount of data that can be written to it.
224 *
225 * @see chainSize
226 *
227 * @return Size of descriptor in bytes.
228 */
229 size_t size() const { return desc.len; }
230
231 /**
232 * Is this descriptor chained to another descriptor?
233 *
234 * @return true if there is a next pointer, false otherwise.
235 */
236 bool hasNext() const { return desc.flags & VRING_DESC_F_NEXT; }
237 /**
238 * Get the pointer to the next descriptor in a chain.
239 *
240 * @return Pointer to the next descriptor or NULL if this is the
241 * last element in a chain.
242 */
243 VirtDescriptor *next() const;
244
245 /** Check if this is a read-only descriptor (incoming data). */
246 bool isIncoming() const { return !isOutgoing(); }
247 /** Check if this is a write-only descriptor (outgoing data). */
248 bool isOutgoing() const { return desc.flags & VRING_DESC_F_WRITE; }
249
250
251 /**
252 * Read the contents of a descriptor chain.
253 *
254 * This method reads the specified number of bytes from a
255 * descriptor chain starting at the this descriptor plus an offset
256 * in bytes. The method automatically follows the links in the
257 * descriptor chain.
258 *
259 * @param offset Offset into the chain (in bytes).
260 * @param dst Pointer to destination buffer.
261 * @param size Size (in bytes).
262 */
263 void chainRead(size_t offset, uint8_t *dst, size_t size) const;
264 /**
265 * Write to a descriptor chain.
266 *
267 * This method writes the specified number of bytes to a
268 * descriptor chain starting at the this descriptor plus an offset
269 * in bytes. The method automatically follows the links in the
270 * descriptor chain.
271 *
272 * @param offset Offset into the chain (in bytes).
273 * @param src Pointer to source buffer.
274 * @param size Size (in bytes).
275 */
276 void chainWrite(size_t offset, const uint8_t *src, size_t size);
277 /**
278 * Retrieve the size of this descriptor chain.
279 *
280 * This method gets the size of a descriptor chain starting at
281 * this descriptor.
282 *
283 * @return Size of descriptor chain in bytes.
284 */
285 size_t chainSize() const;
286 /** @} */
287
288 private:
289 // Remove default constructor
290 VirtDescriptor();
291 // Prevent copying
292 VirtDescriptor(const VirtDescriptor &other);
293
294 /** Pointer to memory proxy */
295 PortProxy *memProxy;
296 /** Pointer to virtqueue owning this descriptor */
297 VirtQueue *queue;
298
299 /** Index in virtqueue */
300 Index _index;
301
302 /** Underlying descriptor */
303 vring_desc desc;
304};
305
306/**
307 * Base wrapper around a virtqueue.
308 *
309 * VirtIO device models typically need to extend this class to
310 * implement their own device queues.
311 *
312 * @note Queues must be registered with
313 * VirtIODeviceBase::registerQueue() to be active.
314 */
315class VirtQueue {
315class VirtQueue : public Serializable {
316public:
317 virtual ~VirtQueue() {};
318
319 /** @{
320 * @name Checkpointing Interface
321 */
316public:
317 virtual ~VirtQueue() {};
318
319 /** @{
320 * @name Checkpointing Interface
321 */
322 virtual void serialize(std::ostream &os);
323 virtual void unserialize(Checkpoint *cp, const std::string &section);
324 /** @} */
322 void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
323 void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
325
326 /** @{
327 * @name Low-level Device Interface
328 */
329 /**
330 * Set the base address of this queue.
331 *
332 * @param address Guest physical base address of the queue.
333 */
334 void setAddress(Addr address);
335 /**
336 * Get the guest physical address of this queue.
337 *
338 * @return Physical address in guest where this queue resides.
339 */
340 Addr getAddress() const { return _address; }
341
342 /**
343 * Get the number of descriptors available in this queue.
344 *
345 * @return Size of queue in descriptors.
346 */
347 uint16_t getSize() const { return _size; }
348
349 /**
350 * Get a pointer to a specific descriptor in the queue.
351 *
352 * @note This interfaces is normally only used by VirtDescriptor
353 * to follow descriptor chains. Device models typically don't need
354 * to use it.
355 *
356 * @return Pointer to a VirtDescriptor.
357 */
358 VirtDescriptor *getDescriptor(VirtDescriptor::Index index) {
359 return &descriptors[index];
360 }
361 /** @} */
362
363 /** @{
364 * @name Device Model Interfaces
365 */
366 /**
367 * Get an incoming descriptor chain from the queue.
368 *
369 * @return Pointer to descriptor on success, NULL if no pending
370 * descriptors are available.
371 */
372 VirtDescriptor *consumeDescriptor();
373 /**
374 * Send a descriptor chain to the guest.
375 *
376 * This method posts a descriptor chain to the guest after a
377 * device model has finished processing it. The device model
378 * typically needs to call VirtIODeviceBase::kick() to deliver
379 * notify tell the guest that the queue has been updated.
380 *
381 * @note The desc parameter must refer to the first descriptor in
382 * a chain that has been retrieved using consumeDescriptor().
383 *
384 * @note The len parameter specified the amount of data produced
385 * by the device model. It seems to be ignored by Linux and it is
386 * not well defined.
387 *
388 * @param desc Start of descriptor chain.
389 * @param len Length of the produced data.
390 */
391 void produceDescriptor(VirtDescriptor *desc, uint32_t len);
392 /** @} */
393
394 /** @{
395 * @name Device Model Callbacks
396 */
397 /**
398 * Notify queue of pending events.
399 *
400 * This method is called by VirtIODeviceBase::onNotify() to notify
401 * the device model of pending data in a virtqueue. The default
402 * implementation of this method iterates over the available
403 * descriptor chains and calls onNotifyDescriptor() for every new
404 * incoming chain.
405 *
406 * Device models should normally overload one of onNotify() and
407 * onNotifyDescriptor().
408 */
409 virtual void onNotify();
410 /**
411 * Notify queue of pending incoming descriptor.
412 *
413 * This method is called by the default implementation of
414 * onNotify() to notify the device model of pending data in a
415 * descriptor chain.
416 *
417 * Device models should normally overload one of onNotify() and
418 * onNotifyDescriptor().
419 */
420 virtual void onNotifyDescriptor(VirtDescriptor *desc) {};
421 /** @} */
422
423 /** @{
424 * @name Debug interfaces
425 */
426 /** Dump the contents of a queue */
427 void dump() const;
428 /** @} */
429
430 /** @{ */
431 /**
432 * Page size used by VirtIO.\ It's hard-coded to 4096 bytes in
433 * the spec for historical reasons.
434 */
435 static const unsigned ALIGN_BITS = 12;
436 static const unsigned ALIGN_SIZE = 1 << ALIGN_BITS;
437 /** @} */
438
439 protected:
440 /**
441 * Instantiate a new virtqueue.
442 *
443 * Instantiate a virtqueue with a fixed size. The size is
444 * specified in descriptors which are defined as 4096 bytes each.
445 *
446 * @param proxy Proxy to the guest physical memory.
447 * @param size Size in descriptors/pages.
448 */
449 VirtQueue(PortProxy &proxy, uint16_t size);
450
451 private:
452 VirtQueue();
453
454 /** Queue size in terms of number of descriptors */
455 const uint16_t _size;
456 /** Base address of the queue */
457 Addr _address;
458 /** Guest physical memory proxy */
459 PortProxy &memProxy;
460
461 private:
462 /**
463 * VirtIO ring buffer wrapper.
464 *
465 * This class wraps a VirtIO ring buffer. The template parameter T
466 * is used to select the data type for the items in the ring (used
467 * or available descriptors).
468 */
469 template<typename T>
470 class VirtRing
471 {
472 public:
473 typedef uint16_t Flags;
474 typedef uint16_t Index;
475
476 struct Header {
477 Flags flags;
478 Index index;
479 } M5_ATTR_PACKED;
480
481 VirtRing<T>(PortProxy &proxy, uint16_t size)
482 : header{0, 0}, ring(size), _proxy(proxy), _base(0) {}
483
484 /**
485 * Set the base address of the VirtIO ring buffer.
486 *
487 * @param addr New host physical address
488 */
489 void setAddress(Addr addr) { _base = addr; }
490
491 /** Update the ring buffer header with data from the guest. */
492 void readHeader() {
493 assert(_base != 0);
494 _proxy.readBlob(_base, (uint8_t *)&header, sizeof(header));
495 header.flags = vtoh_legacy(header.flags);
496 header.index = vtoh_legacy(header.index);
497 }
498
499 void writeHeader() {
500 Header out;
501 assert(_base != 0);
502 out.flags = htov_legacy(header.flags);
503 out.index = htov_legacy(header.index);
504 _proxy.writeBlob(_base, (uint8_t *)&out, sizeof(out));
505 }
506
507 void read() {
508 readHeader();
509
510 /* Read and byte-swap the elements in the ring */
511 T temp[ring.size()];
512 _proxy.readBlob(_base + sizeof(header),
513 (uint8_t *)temp, sizeof(T) * ring.size());
514 for (int i = 0; i < ring.size(); ++i)
515 ring[i] = vtoh_legacy(temp[i]);
516 }
517
518 void write() {
519 assert(_base != 0);
520 /* Create a byte-swapped copy of the ring and write it to
521 * guest memory. */
522 T temp[ring.size()];
523 for (int i = 0; i < ring.size(); ++i)
524 temp[i] = htov_legacy(ring[i]);
525 _proxy.writeBlob(_base + sizeof(header),
526 (uint8_t *)temp, sizeof(T) * ring.size());
527 writeHeader();
528 }
529
530 /** Ring buffer header in host byte order */
531 Header header;
532 /** Elements in ring in host byte order */
533 std::vector<T> ring;
534
535 private:
536 // Remove default constructor
537 VirtRing<T>();
538
539 /** Guest physical memory proxy */
540 PortProxy &_proxy;
541 /** Guest physical base address of the ring buffer */
542 Addr _base;
543 };
544
545 /** Ring of available (incoming) descriptors */
546 VirtRing<VirtDescriptor::Index> avail;
547 /** Ring of used (outgoing) descriptors */
548 VirtRing<struct vring_used_elem> used;
549
550 /** Offset of last consumed descriptor in the VirtQueue::avail
551 * ring */
552 uint16_t _last_avail;
553
554 /** Vector of pre-created descriptors indexed by their index into
555 * the queue. */
556 std::vector<VirtDescriptor> descriptors;
557};
558
559/**
560 * Base class for all VirtIO-based devices.
561 *
562 * This class implements the functionality of the VirtIO 0.9.5
563 * specification. This version of VirtIO is also known as "legacy" in
564 * the VirtIO 1.0 specification from OASIS.
565 *
566 * @see https://github.com/rustyrussell/virtio-spec
567 * @see http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html
568 */
569class VirtIODeviceBase : public SimObject
570{
571 public:
572 typedef uint16_t QueueID;
573 typedef uint32_t FeatureBits;
574 /** This is a VirtQueue address as exposed through the low-level
575 * interface.\ The address needs to be multiplied by the page size
576 * (seems to be hardcoded to 4096 in the spec) to get the real
577 * physical address.
578 */
579 typedef uint16_t VirtAddress;
580 /** Device Type (sometimes known as subsystem ID) */
581 typedef uint16_t DeviceId;
582
583 BitUnion8(DeviceStatus)
584 Bitfield<7> failed;
585 Bitfield<2> driver_ok;
586 Bitfield<1> driver;
587 Bitfield<0> acknowledge;
588 EndBitUnion(DeviceStatus)
589
590 typedef VirtIODeviceBaseParams Params;
591 VirtIODeviceBase(Params *params, DeviceId id, size_t config_size,
592 FeatureBits features);
593 virtual ~VirtIODeviceBase();
594
595 public:
596 /** @{
597 * @name SimObject Interfaces
598 */
324
325 /** @{
326 * @name Low-level Device Interface
327 */
328 /**
329 * Set the base address of this queue.
330 *
331 * @param address Guest physical base address of the queue.
332 */
333 void setAddress(Addr address);
334 /**
335 * Get the guest physical address of this queue.
336 *
337 * @return Physical address in guest where this queue resides.
338 */
339 Addr getAddress() const { return _address; }
340
341 /**
342 * Get the number of descriptors available in this queue.
343 *
344 * @return Size of queue in descriptors.
345 */
346 uint16_t getSize() const { return _size; }
347
348 /**
349 * Get a pointer to a specific descriptor in the queue.
350 *
351 * @note This interfaces is normally only used by VirtDescriptor
352 * to follow descriptor chains. Device models typically don't need
353 * to use it.
354 *
355 * @return Pointer to a VirtDescriptor.
356 */
357 VirtDescriptor *getDescriptor(VirtDescriptor::Index index) {
358 return &descriptors[index];
359 }
360 /** @} */
361
362 /** @{
363 * @name Device Model Interfaces
364 */
365 /**
366 * Get an incoming descriptor chain from the queue.
367 *
368 * @return Pointer to descriptor on success, NULL if no pending
369 * descriptors are available.
370 */
371 VirtDescriptor *consumeDescriptor();
372 /**
373 * Send a descriptor chain to the guest.
374 *
375 * This method posts a descriptor chain to the guest after a
376 * device model has finished processing it. The device model
377 * typically needs to call VirtIODeviceBase::kick() to deliver
378 * notify tell the guest that the queue has been updated.
379 *
380 * @note The desc parameter must refer to the first descriptor in
381 * a chain that has been retrieved using consumeDescriptor().
382 *
383 * @note The len parameter specified the amount of data produced
384 * by the device model. It seems to be ignored by Linux and it is
385 * not well defined.
386 *
387 * @param desc Start of descriptor chain.
388 * @param len Length of the produced data.
389 */
390 void produceDescriptor(VirtDescriptor *desc, uint32_t len);
391 /** @} */
392
393 /** @{
394 * @name Device Model Callbacks
395 */
396 /**
397 * Notify queue of pending events.
398 *
399 * This method is called by VirtIODeviceBase::onNotify() to notify
400 * the device model of pending data in a virtqueue. The default
401 * implementation of this method iterates over the available
402 * descriptor chains and calls onNotifyDescriptor() for every new
403 * incoming chain.
404 *
405 * Device models should normally overload one of onNotify() and
406 * onNotifyDescriptor().
407 */
408 virtual void onNotify();
409 /**
410 * Notify queue of pending incoming descriptor.
411 *
412 * This method is called by the default implementation of
413 * onNotify() to notify the device model of pending data in a
414 * descriptor chain.
415 *
416 * Device models should normally overload one of onNotify() and
417 * onNotifyDescriptor().
418 */
419 virtual void onNotifyDescriptor(VirtDescriptor *desc) {};
420 /** @} */
421
422 /** @{
423 * @name Debug interfaces
424 */
425 /** Dump the contents of a queue */
426 void dump() const;
427 /** @} */
428
429 /** @{ */
430 /**
431 * Page size used by VirtIO.\ It's hard-coded to 4096 bytes in
432 * the spec for historical reasons.
433 */
434 static const unsigned ALIGN_BITS = 12;
435 static const unsigned ALIGN_SIZE = 1 << ALIGN_BITS;
436 /** @} */
437
438 protected:
439 /**
440 * Instantiate a new virtqueue.
441 *
442 * Instantiate a virtqueue with a fixed size. The size is
443 * specified in descriptors which are defined as 4096 bytes each.
444 *
445 * @param proxy Proxy to the guest physical memory.
446 * @param size Size in descriptors/pages.
447 */
448 VirtQueue(PortProxy &proxy, uint16_t size);
449
450 private:
451 VirtQueue();
452
453 /** Queue size in terms of number of descriptors */
454 const uint16_t _size;
455 /** Base address of the queue */
456 Addr _address;
457 /** Guest physical memory proxy */
458 PortProxy &memProxy;
459
460 private:
461 /**
462 * VirtIO ring buffer wrapper.
463 *
464 * This class wraps a VirtIO ring buffer. The template parameter T
465 * is used to select the data type for the items in the ring (used
466 * or available descriptors).
467 */
468 template<typename T>
469 class VirtRing
470 {
471 public:
472 typedef uint16_t Flags;
473 typedef uint16_t Index;
474
475 struct Header {
476 Flags flags;
477 Index index;
478 } M5_ATTR_PACKED;
479
480 VirtRing<T>(PortProxy &proxy, uint16_t size)
481 : header{0, 0}, ring(size), _proxy(proxy), _base(0) {}
482
483 /**
484 * Set the base address of the VirtIO ring buffer.
485 *
486 * @param addr New host physical address
487 */
488 void setAddress(Addr addr) { _base = addr; }
489
490 /** Update the ring buffer header with data from the guest. */
491 void readHeader() {
492 assert(_base != 0);
493 _proxy.readBlob(_base, (uint8_t *)&header, sizeof(header));
494 header.flags = vtoh_legacy(header.flags);
495 header.index = vtoh_legacy(header.index);
496 }
497
498 void writeHeader() {
499 Header out;
500 assert(_base != 0);
501 out.flags = htov_legacy(header.flags);
502 out.index = htov_legacy(header.index);
503 _proxy.writeBlob(_base, (uint8_t *)&out, sizeof(out));
504 }
505
506 void read() {
507 readHeader();
508
509 /* Read and byte-swap the elements in the ring */
510 T temp[ring.size()];
511 _proxy.readBlob(_base + sizeof(header),
512 (uint8_t *)temp, sizeof(T) * ring.size());
513 for (int i = 0; i < ring.size(); ++i)
514 ring[i] = vtoh_legacy(temp[i]);
515 }
516
517 void write() {
518 assert(_base != 0);
519 /* Create a byte-swapped copy of the ring and write it to
520 * guest memory. */
521 T temp[ring.size()];
522 for (int i = 0; i < ring.size(); ++i)
523 temp[i] = htov_legacy(ring[i]);
524 _proxy.writeBlob(_base + sizeof(header),
525 (uint8_t *)temp, sizeof(T) * ring.size());
526 writeHeader();
527 }
528
529 /** Ring buffer header in host byte order */
530 Header header;
531 /** Elements in ring in host byte order */
532 std::vector<T> ring;
533
534 private:
535 // Remove default constructor
536 VirtRing<T>();
537
538 /** Guest physical memory proxy */
539 PortProxy &_proxy;
540 /** Guest physical base address of the ring buffer */
541 Addr _base;
542 };
543
544 /** Ring of available (incoming) descriptors */
545 VirtRing<VirtDescriptor::Index> avail;
546 /** Ring of used (outgoing) descriptors */
547 VirtRing<struct vring_used_elem> used;
548
549 /** Offset of last consumed descriptor in the VirtQueue::avail
550 * ring */
551 uint16_t _last_avail;
552
553 /** Vector of pre-created descriptors indexed by their index into
554 * the queue. */
555 std::vector<VirtDescriptor> descriptors;
556};
557
558/**
559 * Base class for all VirtIO-based devices.
560 *
561 * This class implements the functionality of the VirtIO 0.9.5
562 * specification. This version of VirtIO is also known as "legacy" in
563 * the VirtIO 1.0 specification from OASIS.
564 *
565 * @see https://github.com/rustyrussell/virtio-spec
566 * @see http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html
567 */
568class VirtIODeviceBase : public SimObject
569{
570 public:
571 typedef uint16_t QueueID;
572 typedef uint32_t FeatureBits;
573 /** This is a VirtQueue address as exposed through the low-level
574 * interface.\ The address needs to be multiplied by the page size
575 * (seems to be hardcoded to 4096 in the spec) to get the real
576 * physical address.
577 */
578 typedef uint16_t VirtAddress;
579 /** Device Type (sometimes known as subsystem ID) */
580 typedef uint16_t DeviceId;
581
582 BitUnion8(DeviceStatus)
583 Bitfield<7> failed;
584 Bitfield<2> driver_ok;
585 Bitfield<1> driver;
586 Bitfield<0> acknowledge;
587 EndBitUnion(DeviceStatus)
588
589 typedef VirtIODeviceBaseParams Params;
590 VirtIODeviceBase(Params *params, DeviceId id, size_t config_size,
591 FeatureBits features);
592 virtual ~VirtIODeviceBase();
593
594 public:
595 /** @{
596 * @name SimObject Interfaces
597 */
599
600 void serialize(std::ostream &os);
601 void unserialize(Checkpoint *cp, const std::string &section);
602
598 void serialize(CheckpointOut &cp) const M5_ATTR_OVERRIDE;
599 void unserialize(CheckpointIn &cp) M5_ATTR_OVERRIDE;
603 /** @} */
604
605
606 protected:
607 /** @{
608 * @name Device Model Interfaces
609 */
610
611 /**
612 * Inform the guest of available buffers.
613 *
614 * When a device model has finished processing incoming buffers
615 * (after onNotify has been called), it typically needs to inform
616 * the guest that there are new pending outgoing buffers. The
617 * method used to inform the guest is transport dependent, but is
618 * typically through an interrupt. Device models call this method
619 * to tell the transport interface to notify the guest.
620 */
621 void kick() {
622 assert(transKick);
623 transKick->process();
624 };
625
626 /**
627 * Register a new VirtQueue with the device model.
628 *
629 * Devices typically register at least one VirtQueue to use for
630 * communication with the guest. This <i>must</i> be done from the
631 * constructor since the number of queues are assumed to be
632 * constant throughout the lifetime of the device.
633 *
634 * @warning This method may only be called from the device model
635 * constructor.
636 */
637 void registerQueue(VirtQueue &queue);
638
639
640 /**
641 * Feature set accepted by the guest.
642 *
643 * When the guest starts the driver for the device, it starts by
644 * negotiating features. The device first offers a set of features
645 * (see deviceFeatures), the driver then notifies the device of
646 * which features it accepted. The base class will automatically
647 * accept any feature set that is a subset of the features offered
648 * by the device.
649 */
650 FeatureBits guestFeatures;
651 /** @} */
652
653 public:
654 /** @{
655 * @name Optional VirtIO Interfaces
656 */
657 /**
658 * Read from the configuration space of a device.
659 *
660 * This method is called by the transport interface to read data
661 * from a device model's configuration space. The device model
662 * should use the cfgOffset parameter as the offset into its
663 * configuration space.
664 *
665 * @warning The address in the packet should not be used to
666 * determine the offset into a device's configuration space.
667 *
668 * @param pkt Read request packet.
669 * @param cfgOffset Offset into the device's configuration space.
670 */
671 virtual void readConfig(PacketPtr pkt, Addr cfgOffset);
672 /**
673 * Write to the configuration space of a device.
674 *
675 * This method is called by the transport interface to write data
676 * into a device model's configuration space. The device model
677 * should use the cfgOffset parameter as the offset into its
678 * configuration space.
679 *
680 * @warning The address in the packet should not be used to
681 * determine the offset into a device's configuration space.
682 *
683 * @param pkt Write request packet.
684 * @param cfgOffset Offset into the device's configuration space.
685 */
686 virtual void writeConfig(PacketPtr pkt, Addr cfgOffset);
687
688 /**
689 * Driver-request device reset.
690 *
691 * The device driver may reset a device by writing zero to the
692 * device status register (using setDeviceStatus()), which causes
693 * this method to be called. Device models overriding this method
694 * <i>must</i> ensure that the reset method of the base class is
695 * called when the device is reset.
696 *
697 * @note Always call the reset method of the base class from
698 * device-specific reset methods.
699 */
700 virtual void reset();
701 /** @} */
702
703 protected:
704 /** @{
705 * @name Device Model Helpers
706 */
707
708 /**
709 * Read configuration data from a device structure.
710 *
711 * @param pkt Read request packet.
712 * @param cfgOffset Offset into the device's configuration space.
713 * @param cfg Device configuration
714 */
715 void readConfigBlob(PacketPtr pkt, Addr cfgOffset, const uint8_t *cfg);
716
717 /**
718 * Write configuration data to a device structure.
719 *
720 * @param pkt Write request packet.
721 * @param cfgOffset Offset into the device's configuration space.
722 * @param cfg Device configuration
723 */
724 void writeConfigBlob(PacketPtr pkt, Addr cfgOffset, uint8_t *cfg);
725
726 /** @} */
727
728 public:
729 /** @{
730 * @name VirtIO Transport Interfaces
731 */
732 /**
733 * Register a callback to kick the guest through the transport
734 * interface.
735 *
736 * @param c Callback into transport interface.
737 */
738 void registerKickCallback(Callback *c) {
739 assert(!transKick);
740 transKick = c;
741 }
742
743
744 /**
745 * Driver is requesting service.
746 *
747 * This method is called by the underlying hardware interface
748 * (e.g., PciVirtIO or MmmioVirtIO) to notify a device of pending
749 * incoming descriptors.
750 *
751 * @param index ID of the queue with pending actions.
752 */
753 void onNotify(QueueID index);
754
755
756 /**
757 * Change currently active queue.
758 *
759 * The transport interface works on a queue at a time. The
760 * currently active queue is decided by the value of the queue
761 * select field in a device.
762 *
763 * @param idx ID of the queue to select.
764 */
765 void setQueueSelect(QueueID idx) { _queueSelect = idx; }
766 /**
767 * Get the currently active queue.
768 *
769 * The transport interface works on a queue at a time. The
770 * currently active queue is decided by the value of the queue
771 * select field in a device.
772 *
773 * @return The ID of the currently active queue.
774 */
775 QueueID getQueueSelect() const { return _queueSelect; }
776
777 /**
778 * Change the host physical address of the currently active queue.
779 *
780 * @note The new address is specified in multiples of the page
781 * size (fixed to 4096 bytes in the standard). For example, if the
782 * address 10 is selected, the actual host physical address will
783 * be 40960.
784 *
785 * @see setQueueSelect
786 * @see getQueueSelect
787 *
788 * @param address New address of the currently active queue (in
789 * pages).
790 */
791 void setQueueAddress(uint32_t address);
792 /**
793 * Get the host physical address of the currently active queue.
794 *
795 * @note The new address is specified in multiples of the page
796 * size (fixed to 4096 bytes in the standard). For example, if the
797 * address 10 is selected, the actual host physical address will
798 * be 40960.
799 *
800 * @see setQueueSelect
801 * @see getQueueSelect
802 *
803 * @return Address of the currently active queue (in pages).
804 */
805 uint32_t getQueueAddress() const;
806
807 /**
808 * Get the size (descriptors) of the currently active queue.
809 *
810 * @return Size of the currently active queue in number of
811 * descriptors.
812 */
813 uint16_t getQueueSize() const { return getCurrentQueue().getSize(); }
814
815 /**
816 * Update device status and optionally reset device.
817 *
818 * The special device status of 0 is used to reset the device by
819 * calling reset().
820 *
821 * @param status New device status.
822 */
823 void setDeviceStatus(DeviceStatus status);
824
825 /**
826 * Retrieve the device status.
827 *
828 * @return Device status.
829 */
830 DeviceStatus getDeviceStatus() const { return _deviceStatus; }
831
832 /**
833 * Set feature bits accepted by the guest driver.
834 *
835 * This enables a subset of the features offered by the device
836 * model through the getGuestFeatures() interface.
837 */
838 void setGuestFeatures(FeatureBits features);
839
840 /**
841 * Get features accepted by the guest driver.
842 *
843 * @return Currently active features.
844 */
845 FeatureBits getGuestFeatures() const { return guestFeatures; }
846
847 /** Device ID (sometimes known as subsystem ID) */
848 const DeviceId deviceId;
849
850 /** Size of the device's configuration space */
851 const size_t configSize;
852
853 /** Feature set offered by the device */
854 const FeatureBits deviceFeatures;
855 /** @} */
856
857 private:
858 /** Convenience method to get the currently selected queue */
859 const VirtQueue &getCurrentQueue() const;
860 /** Convenience method to get the currently selected queue */
861 VirtQueue &getCurrentQueue();
862
863 /**
864 * Status of the device
865 *
866 * @see getDeviceStatus
867 * @see setDeviceStatus
868 */
869 DeviceStatus _deviceStatus;
870
871 /** Queue select register (set by guest) */
872 QueueID _queueSelect;
873
874 /** List of virtual queues supported by this device */
875 std::vector<VirtQueue *> _queues;
876
877 /** Callbacks to kick the guest through the transport layer */
878 Callback *transKick;
879};
880
881#endif // __DEV_VIRTIO_BASE_HH__
600 /** @} */
601
602
603 protected:
604 /** @{
605 * @name Device Model Interfaces
606 */
607
608 /**
609 * Inform the guest of available buffers.
610 *
611 * When a device model has finished processing incoming buffers
612 * (after onNotify has been called), it typically needs to inform
613 * the guest that there are new pending outgoing buffers. The
614 * method used to inform the guest is transport dependent, but is
615 * typically through an interrupt. Device models call this method
616 * to tell the transport interface to notify the guest.
617 */
618 void kick() {
619 assert(transKick);
620 transKick->process();
621 };
622
623 /**
624 * Register a new VirtQueue with the device model.
625 *
626 * Devices typically register at least one VirtQueue to use for
627 * communication with the guest. This <i>must</i> be done from the
628 * constructor since the number of queues are assumed to be
629 * constant throughout the lifetime of the device.
630 *
631 * @warning This method may only be called from the device model
632 * constructor.
633 */
634 void registerQueue(VirtQueue &queue);
635
636
637 /**
638 * Feature set accepted by the guest.
639 *
640 * When the guest starts the driver for the device, it starts by
641 * negotiating features. The device first offers a set of features
642 * (see deviceFeatures), the driver then notifies the device of
643 * which features it accepted. The base class will automatically
644 * accept any feature set that is a subset of the features offered
645 * by the device.
646 */
647 FeatureBits guestFeatures;
648 /** @} */
649
650 public:
651 /** @{
652 * @name Optional VirtIO Interfaces
653 */
654 /**
655 * Read from the configuration space of a device.
656 *
657 * This method is called by the transport interface to read data
658 * from a device model's configuration space. The device model
659 * should use the cfgOffset parameter as the offset into its
660 * configuration space.
661 *
662 * @warning The address in the packet should not be used to
663 * determine the offset into a device's configuration space.
664 *
665 * @param pkt Read request packet.
666 * @param cfgOffset Offset into the device's configuration space.
667 */
668 virtual void readConfig(PacketPtr pkt, Addr cfgOffset);
669 /**
670 * Write to the configuration space of a device.
671 *
672 * This method is called by the transport interface to write data
673 * into a device model's configuration space. The device model
674 * should use the cfgOffset parameter as the offset into its
675 * configuration space.
676 *
677 * @warning The address in the packet should not be used to
678 * determine the offset into a device's configuration space.
679 *
680 * @param pkt Write request packet.
681 * @param cfgOffset Offset into the device's configuration space.
682 */
683 virtual void writeConfig(PacketPtr pkt, Addr cfgOffset);
684
685 /**
686 * Driver-request device reset.
687 *
688 * The device driver may reset a device by writing zero to the
689 * device status register (using setDeviceStatus()), which causes
690 * this method to be called. Device models overriding this method
691 * <i>must</i> ensure that the reset method of the base class is
692 * called when the device is reset.
693 *
694 * @note Always call the reset method of the base class from
695 * device-specific reset methods.
696 */
697 virtual void reset();
698 /** @} */
699
700 protected:
701 /** @{
702 * @name Device Model Helpers
703 */
704
705 /**
706 * Read configuration data from a device structure.
707 *
708 * @param pkt Read request packet.
709 * @param cfgOffset Offset into the device's configuration space.
710 * @param cfg Device configuration
711 */
712 void readConfigBlob(PacketPtr pkt, Addr cfgOffset, const uint8_t *cfg);
713
714 /**
715 * Write configuration data to a device structure.
716 *
717 * @param pkt Write request packet.
718 * @param cfgOffset Offset into the device's configuration space.
719 * @param cfg Device configuration
720 */
721 void writeConfigBlob(PacketPtr pkt, Addr cfgOffset, uint8_t *cfg);
722
723 /** @} */
724
725 public:
726 /** @{
727 * @name VirtIO Transport Interfaces
728 */
729 /**
730 * Register a callback to kick the guest through the transport
731 * interface.
732 *
733 * @param c Callback into transport interface.
734 */
735 void registerKickCallback(Callback *c) {
736 assert(!transKick);
737 transKick = c;
738 }
739
740
741 /**
742 * Driver is requesting service.
743 *
744 * This method is called by the underlying hardware interface
745 * (e.g., PciVirtIO or MmmioVirtIO) to notify a device of pending
746 * incoming descriptors.
747 *
748 * @param index ID of the queue with pending actions.
749 */
750 void onNotify(QueueID index);
751
752
753 /**
754 * Change currently active queue.
755 *
756 * The transport interface works on a queue at a time. The
757 * currently active queue is decided by the value of the queue
758 * select field in a device.
759 *
760 * @param idx ID of the queue to select.
761 */
762 void setQueueSelect(QueueID idx) { _queueSelect = idx; }
763 /**
764 * Get the currently active queue.
765 *
766 * The transport interface works on a queue at a time. The
767 * currently active queue is decided by the value of the queue
768 * select field in a device.
769 *
770 * @return The ID of the currently active queue.
771 */
772 QueueID getQueueSelect() const { return _queueSelect; }
773
774 /**
775 * Change the host physical address of the currently active queue.
776 *
777 * @note The new address is specified in multiples of the page
778 * size (fixed to 4096 bytes in the standard). For example, if the
779 * address 10 is selected, the actual host physical address will
780 * be 40960.
781 *
782 * @see setQueueSelect
783 * @see getQueueSelect
784 *
785 * @param address New address of the currently active queue (in
786 * pages).
787 */
788 void setQueueAddress(uint32_t address);
789 /**
790 * Get the host physical address of the currently active queue.
791 *
792 * @note The new address is specified in multiples of the page
793 * size (fixed to 4096 bytes in the standard). For example, if the
794 * address 10 is selected, the actual host physical address will
795 * be 40960.
796 *
797 * @see setQueueSelect
798 * @see getQueueSelect
799 *
800 * @return Address of the currently active queue (in pages).
801 */
802 uint32_t getQueueAddress() const;
803
804 /**
805 * Get the size (descriptors) of the currently active queue.
806 *
807 * @return Size of the currently active queue in number of
808 * descriptors.
809 */
810 uint16_t getQueueSize() const { return getCurrentQueue().getSize(); }
811
812 /**
813 * Update device status and optionally reset device.
814 *
815 * The special device status of 0 is used to reset the device by
816 * calling reset().
817 *
818 * @param status New device status.
819 */
820 void setDeviceStatus(DeviceStatus status);
821
822 /**
823 * Retrieve the device status.
824 *
825 * @return Device status.
826 */
827 DeviceStatus getDeviceStatus() const { return _deviceStatus; }
828
829 /**
830 * Set feature bits accepted by the guest driver.
831 *
832 * This enables a subset of the features offered by the device
833 * model through the getGuestFeatures() interface.
834 */
835 void setGuestFeatures(FeatureBits features);
836
837 /**
838 * Get features accepted by the guest driver.
839 *
840 * @return Currently active features.
841 */
842 FeatureBits getGuestFeatures() const { return guestFeatures; }
843
844 /** Device ID (sometimes known as subsystem ID) */
845 const DeviceId deviceId;
846
847 /** Size of the device's configuration space */
848 const size_t configSize;
849
850 /** Feature set offered by the device */
851 const FeatureBits deviceFeatures;
852 /** @} */
853
854 private:
855 /** Convenience method to get the currently selected queue */
856 const VirtQueue &getCurrentQueue() const;
857 /** Convenience method to get the currently selected queue */
858 VirtQueue &getCurrentQueue();
859
860 /**
861 * Status of the device
862 *
863 * @see getDeviceStatus
864 * @see setDeviceStatus
865 */
866 DeviceStatus _deviceStatus;
867
868 /** Queue select register (set by guest) */
869 QueueID _queueSelect;
870
871 /** List of virtual queues supported by this device */
872 std::vector<VirtQueue *> _queues;
873
874 /** Callbacks to kick the guest through the transport layer */
875 Callback *transKick;
876};
877
878#endif // __DEV_VIRTIO_BASE_HH__