base.hh revision 10388
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 {
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    /** @} */
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            : 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     */
599
600    void serialize(std::ostream &os);
601    void unserialize(Checkpoint *cp, const std::string &section);
602
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__
882