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