110388SAndreas.Sandberg@ARM.com/* 212114Ssascha.bischoff@arm.com * Copyright (c) 2014, 2016-2017 ARM Limited 310388SAndreas.Sandberg@ARM.com * All rights reserved 410388SAndreas.Sandberg@ARM.com * 510388SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall 610388SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual 710388SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating 810388SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software 910388SAndreas.Sandberg@ARM.com * licensed hereunder. You may use the software subject to the license 1010388SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated 1110388SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software, 1210388SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form. 1310388SAndreas.Sandberg@ARM.com * 1410388SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without 1510388SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are 1610388SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright 1710388SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer; 1810388SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright 1910388SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the 2010388SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution; 2110388SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its 2210388SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from 2310388SAndreas.Sandberg@ARM.com * this software without specific prior written permission. 2410388SAndreas.Sandberg@ARM.com * 2510388SAndreas.Sandberg@ARM.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2610388SAndreas.Sandberg@ARM.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2710388SAndreas.Sandberg@ARM.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2810388SAndreas.Sandberg@ARM.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910388SAndreas.Sandberg@ARM.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010388SAndreas.Sandberg@ARM.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3110388SAndreas.Sandberg@ARM.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3210388SAndreas.Sandberg@ARM.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3310388SAndreas.Sandberg@ARM.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3410388SAndreas.Sandberg@ARM.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3510388SAndreas.Sandberg@ARM.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3610388SAndreas.Sandberg@ARM.com * 3710388SAndreas.Sandberg@ARM.com * Authors: Andreas Sandberg 3810388SAndreas.Sandberg@ARM.com */ 3910388SAndreas.Sandberg@ARM.com 4010388SAndreas.Sandberg@ARM.com#ifndef __DEV_VIRTIO_BASE_HH__ 4110388SAndreas.Sandberg@ARM.com#define __DEV_VIRTIO_BASE_HH__ 4210388SAndreas.Sandberg@ARM.com 4310388SAndreas.Sandberg@ARM.com#include "arch/isa_traits.hh" 4410388SAndreas.Sandberg@ARM.com#include "base/bitunion.hh" 4510388SAndreas.Sandberg@ARM.com#include "base/callback.hh" 4610388SAndreas.Sandberg@ARM.com#include "dev/virtio/virtio_ring.h" 4710388SAndreas.Sandberg@ARM.com#include "mem/port_proxy.hh" 4810388SAndreas.Sandberg@ARM.com#include "sim/sim_object.hh" 4910388SAndreas.Sandberg@ARM.com 5010388SAndreas.Sandberg@ARM.comstruct VirtIODeviceBaseParams; 5111931Sandreas.sandberg@arm.comstruct VirtIODummyDeviceParams; 5211931Sandreas.sandberg@arm.com 5310388SAndreas.Sandberg@ARM.comclass VirtQueue; 5410388SAndreas.Sandberg@ARM.com 5510388SAndreas.Sandberg@ARM.com/** @{ 5610388SAndreas.Sandberg@ARM.com * @name VirtIO endian conversion helpers 5710388SAndreas.Sandberg@ARM.com * 5810388SAndreas.Sandberg@ARM.com * VirtIO prior to version 1.0 (legacy versions) normally send values 5910388SAndreas.Sandberg@ARM.com * to the host in the guest systems native byte order. This is going 6010388SAndreas.Sandberg@ARM.com * to change in version 1.0 which mandates little endian. We currently 6110388SAndreas.Sandberg@ARM.com * only support the legacy version of VirtIO (the new and shiny 6210388SAndreas.Sandberg@ARM.com * standard is still in a draft state and not implemented by the 6310388SAndreas.Sandberg@ARM.com * kernel). Once we support the new standard, we should negotiate the 6410388SAndreas.Sandberg@ARM.com * VirtIO version with the guest and automatically use the right type 6510388SAndreas.Sandberg@ARM.com * of byte swapping. 6610388SAndreas.Sandberg@ARM.com */ 6710388SAndreas.Sandberg@ARM.com 6810388SAndreas.Sandberg@ARM.com/** Convert legacy VirtIO endianness to host endianness. */ 6910388SAndreas.Sandberg@ARM.comtemplate <typename T> inline T 7010388SAndreas.Sandberg@ARM.comvtoh_legacy(T v) { 7110388SAndreas.Sandberg@ARM.com return TheISA::gtoh(v); 7210388SAndreas.Sandberg@ARM.com} 7310388SAndreas.Sandberg@ARM.com 7410388SAndreas.Sandberg@ARM.com/** Convert host endianness to legacy VirtIO endianness. */ 7510388SAndreas.Sandberg@ARM.comtemplate <typename T> inline T 7610388SAndreas.Sandberg@ARM.comhtov_legacy(T v) { 7710388SAndreas.Sandberg@ARM.com return TheISA::htog(v); 7810388SAndreas.Sandberg@ARM.com} 7910388SAndreas.Sandberg@ARM.com 8010388SAndreas.Sandberg@ARM.com 8110388SAndreas.Sandberg@ARM.comtemplate <> inline vring_used_elem 8210388SAndreas.Sandberg@ARM.comvtoh_legacy(vring_used_elem v) { 8310388SAndreas.Sandberg@ARM.com v.id = vtoh_legacy(v.id); 8410388SAndreas.Sandberg@ARM.com v.len = vtoh_legacy(v.len); 8510388SAndreas.Sandberg@ARM.com return v; 8610388SAndreas.Sandberg@ARM.com} 8710388SAndreas.Sandberg@ARM.com 8810388SAndreas.Sandberg@ARM.comtemplate <> inline vring_used_elem 8910388SAndreas.Sandberg@ARM.comhtov_legacy(vring_used_elem v) { 9010388SAndreas.Sandberg@ARM.com v.id = htov_legacy(v.id); 9110388SAndreas.Sandberg@ARM.com v.len = htov_legacy(v.len); 9210388SAndreas.Sandberg@ARM.com return v; 9310388SAndreas.Sandberg@ARM.com} 9410388SAndreas.Sandberg@ARM.com 9510388SAndreas.Sandberg@ARM.comtemplate <> inline vring_desc 9610388SAndreas.Sandberg@ARM.comvtoh_legacy(vring_desc v) { 9710388SAndreas.Sandberg@ARM.com v.addr = vtoh_legacy(v.addr); 9810388SAndreas.Sandberg@ARM.com v.len = vtoh_legacy(v.len); 9910388SAndreas.Sandberg@ARM.com v.flags = vtoh_legacy(v.flags); 10010388SAndreas.Sandberg@ARM.com v.next = vtoh_legacy(v.next); 10110388SAndreas.Sandberg@ARM.com return v; 10210388SAndreas.Sandberg@ARM.com} 10310388SAndreas.Sandberg@ARM.com 10410388SAndreas.Sandberg@ARM.comtemplate <> inline vring_desc 10510388SAndreas.Sandberg@ARM.comhtov_legacy(vring_desc v) { 10610388SAndreas.Sandberg@ARM.com v.addr = htov_legacy(v.addr); 10710388SAndreas.Sandberg@ARM.com v.len = htov_legacy(v.len); 10810388SAndreas.Sandberg@ARM.com v.flags = htov_legacy(v.flags); 10910388SAndreas.Sandberg@ARM.com v.next = htov_legacy(v.next); 11010388SAndreas.Sandberg@ARM.com return v; 11110388SAndreas.Sandberg@ARM.com} 11210388SAndreas.Sandberg@ARM.com 11310388SAndreas.Sandberg@ARM.com/** @} */ 11410388SAndreas.Sandberg@ARM.com 11510388SAndreas.Sandberg@ARM.com/** 11610388SAndreas.Sandberg@ARM.com * VirtIO descriptor (chain) wrapper 11710388SAndreas.Sandberg@ARM.com * 11810388SAndreas.Sandberg@ARM.com * Communication in VirtIO takes place by sending and receiving chains 11910388SAndreas.Sandberg@ARM.com * of so called descriptors using device queues. The queue is 12010388SAndreas.Sandberg@ARM.com * responsible for sending a descriptor chain from the guest to the 12110388SAndreas.Sandberg@ARM.com * host and later sending it back to the guest. The descriptor chain 12210388SAndreas.Sandberg@ARM.com * itself can be thought of as a linked list of buffers (descriptors) 12310388SAndreas.Sandberg@ARM.com * that are read only (isIncoming() is true) or write only 12410388SAndreas.Sandberg@ARM.com * (isOutgoing() is true). A single chain may contain any mix of input 12510388SAndreas.Sandberg@ARM.com * and output buffers. 12610388SAndreas.Sandberg@ARM.com * 12710388SAndreas.Sandberg@ARM.com * The descriptor wrapper is normally <i>only</i> instantiated by the 12810388SAndreas.Sandberg@ARM.com * virtqueue wrapper (VirtQueue) and should never be instantiated in 12910388SAndreas.Sandberg@ARM.com * device models. The VirtQueue also ensures that the descriptor 13010388SAndreas.Sandberg@ARM.com * wrapper is re-populated with new data from the guest by calling 13110388SAndreas.Sandberg@ARM.com * updateChain() whenever a new descriptor chain is passed to the host 13210388SAndreas.Sandberg@ARM.com * (VirtQueue::consumeDescriptor()). The updateChain() method 13310388SAndreas.Sandberg@ARM.com * automatically does some sanity checks on the descriptor chain to 13410388SAndreas.Sandberg@ARM.com * detect loops. 13510388SAndreas.Sandberg@ARM.com */ 13610388SAndreas.Sandberg@ARM.comclass VirtDescriptor 13710388SAndreas.Sandberg@ARM.com{ 13810388SAndreas.Sandberg@ARM.com public: 13910388SAndreas.Sandberg@ARM.com /** Descriptor index in virtqueue */ 14010388SAndreas.Sandberg@ARM.com typedef uint16_t Index; 14110388SAndreas.Sandberg@ARM.com 14210388SAndreas.Sandberg@ARM.com /** @{ 14310388SAndreas.Sandberg@ARM.com * @name VirtIO Descriptor <-> Queue Interface 14410388SAndreas.Sandberg@ARM.com */ 14510388SAndreas.Sandberg@ARM.com /** 14610388SAndreas.Sandberg@ARM.com * Create a descriptor wrapper. 14710388SAndreas.Sandberg@ARM.com * 14810388SAndreas.Sandberg@ARM.com * @param memProxy Proxy to the guest physical memory. 14910388SAndreas.Sandberg@ARM.com * @param queue Queue owning this descriptor. 15010388SAndreas.Sandberg@ARM.com * @param index Index within the queue. 15110388SAndreas.Sandberg@ARM.com */ 15210388SAndreas.Sandberg@ARM.com VirtDescriptor(PortProxy &memProxy, VirtQueue &queue, Index index); 15310388SAndreas.Sandberg@ARM.com // WORKAROUND: The noexcept declaration works around a bug where 15410388SAndreas.Sandberg@ARM.com // gcc 4.7 tries to call the wrong constructor when emplacing 15510388SAndreas.Sandberg@ARM.com // something into a vector. 15610388SAndreas.Sandberg@ARM.com VirtDescriptor(VirtDescriptor &&other) noexcept; 15710388SAndreas.Sandberg@ARM.com ~VirtDescriptor() noexcept; 15810388SAndreas.Sandberg@ARM.com 15910388SAndreas.Sandberg@ARM.com VirtDescriptor &operator=(VirtDescriptor &&rhs) noexcept; 16010388SAndreas.Sandberg@ARM.com 16110388SAndreas.Sandberg@ARM.com /** Get the descriptor's index into the virtqueue. */ 16210388SAndreas.Sandberg@ARM.com Index index() const { return _index; } 16310388SAndreas.Sandberg@ARM.com 16410388SAndreas.Sandberg@ARM.com /** Populate this descriptor with data from the guest. */ 16510388SAndreas.Sandberg@ARM.com void update(); 16610388SAndreas.Sandberg@ARM.com 16710388SAndreas.Sandberg@ARM.com /** Populate this descriptor chain with data from the guest. */ 16810388SAndreas.Sandberg@ARM.com void updateChain(); 16910388SAndreas.Sandberg@ARM.com /** @} */ 17010388SAndreas.Sandberg@ARM.com 17110388SAndreas.Sandberg@ARM.com /** @{ 17210388SAndreas.Sandberg@ARM.com * @name Debug interfaces 17310388SAndreas.Sandberg@ARM.com */ 17410388SAndreas.Sandberg@ARM.com /** 17510388SAndreas.Sandberg@ARM.com * Dump the contents of a descriptor 17610388SAndreas.Sandberg@ARM.com */ 17710388SAndreas.Sandberg@ARM.com void dump() const; 17810388SAndreas.Sandberg@ARM.com /** 17910388SAndreas.Sandberg@ARM.com * Dump the contents of a descriptor chain starting at this 18010388SAndreas.Sandberg@ARM.com * descriptor. 18110388SAndreas.Sandberg@ARM.com */ 18210388SAndreas.Sandberg@ARM.com void dumpChain() const; 18310388SAndreas.Sandberg@ARM.com /** @} */ 18410388SAndreas.Sandberg@ARM.com 18510388SAndreas.Sandberg@ARM.com 18610388SAndreas.Sandberg@ARM.com /** @{ 18710388SAndreas.Sandberg@ARM.com * @name Device Model Interfaces 18810388SAndreas.Sandberg@ARM.com */ 18910388SAndreas.Sandberg@ARM.com /** 19010388SAndreas.Sandberg@ARM.com * Read the contents of a descriptor. 19110388SAndreas.Sandberg@ARM.com * 19210388SAndreas.Sandberg@ARM.com * This method copies the contents of a descriptor into a buffer 19310388SAndreas.Sandberg@ARM.com * within gem5. Devices should typically use chainRead() instead 19410388SAndreas.Sandberg@ARM.com * as it automatically follows the descriptor chain to read the 19510388SAndreas.Sandberg@ARM.com * desired number of bytes. 19610388SAndreas.Sandberg@ARM.com * 19710388SAndreas.Sandberg@ARM.com * @see chainRead 19810388SAndreas.Sandberg@ARM.com * 19910388SAndreas.Sandberg@ARM.com * @param offset Offset into the descriptor. 20010388SAndreas.Sandberg@ARM.com * @param dst Destination buffer. 20110388SAndreas.Sandberg@ARM.com * @param size Amount of data to read (in bytes). 20210388SAndreas.Sandberg@ARM.com */ 20310388SAndreas.Sandberg@ARM.com void read(size_t offset, uint8_t *dst, size_t size) const; 20410388SAndreas.Sandberg@ARM.com /** 20510388SAndreas.Sandberg@ARM.com * Write to the contents of a descriptor. 20610388SAndreas.Sandberg@ARM.com * 20710388SAndreas.Sandberg@ARM.com * This method copies the contents of a descriptor into a buffer 20810388SAndreas.Sandberg@ARM.com * within gem5. Devices should typically use chainWrite() instead 20910388SAndreas.Sandberg@ARM.com * as it automatically follows the descriptor chain to read the 21010388SAndreas.Sandberg@ARM.com * desired number of bytes. 21110388SAndreas.Sandberg@ARM.com * 21210388SAndreas.Sandberg@ARM.com * @see chainWrite 21310388SAndreas.Sandberg@ARM.com * 21410388SAndreas.Sandberg@ARM.com * @param offset Offset into the descriptor. 21510388SAndreas.Sandberg@ARM.com * @param src Source buffer. 21610388SAndreas.Sandberg@ARM.com * @param size Amount of data to read (in bytes). 21710388SAndreas.Sandberg@ARM.com */ 21810388SAndreas.Sandberg@ARM.com void write(size_t offset, const uint8_t *src, size_t size); 21910388SAndreas.Sandberg@ARM.com /** 22010388SAndreas.Sandberg@ARM.com * Retrieve the size of this descriptor. 22110388SAndreas.Sandberg@ARM.com * 22210388SAndreas.Sandberg@ARM.com * This method gets the size of a single descriptor. For incoming 22310388SAndreas.Sandberg@ARM.com * data, it corresponds to the amount of data that can be read 22410388SAndreas.Sandberg@ARM.com * from the descriptor. For outgoing data, it corresponds to the 22510388SAndreas.Sandberg@ARM.com * amount of data that can be written to it. 22610388SAndreas.Sandberg@ARM.com * 22710388SAndreas.Sandberg@ARM.com * @see chainSize 22810388SAndreas.Sandberg@ARM.com * 22910388SAndreas.Sandberg@ARM.com * @return Size of descriptor in bytes. 23010388SAndreas.Sandberg@ARM.com */ 23110388SAndreas.Sandberg@ARM.com size_t size() const { return desc.len; } 23210388SAndreas.Sandberg@ARM.com 23310388SAndreas.Sandberg@ARM.com /** 23410388SAndreas.Sandberg@ARM.com * Is this descriptor chained to another descriptor? 23510388SAndreas.Sandberg@ARM.com * 23610388SAndreas.Sandberg@ARM.com * @return true if there is a next pointer, false otherwise. 23710388SAndreas.Sandberg@ARM.com */ 23810388SAndreas.Sandberg@ARM.com bool hasNext() const { return desc.flags & VRING_DESC_F_NEXT; } 23910388SAndreas.Sandberg@ARM.com /** 24010388SAndreas.Sandberg@ARM.com * Get the pointer to the next descriptor in a chain. 24110388SAndreas.Sandberg@ARM.com * 24210388SAndreas.Sandberg@ARM.com * @return Pointer to the next descriptor or NULL if this is the 24310388SAndreas.Sandberg@ARM.com * last element in a chain. 24410388SAndreas.Sandberg@ARM.com */ 24510388SAndreas.Sandberg@ARM.com VirtDescriptor *next() const; 24610388SAndreas.Sandberg@ARM.com 24710388SAndreas.Sandberg@ARM.com /** Check if this is a read-only descriptor (incoming data). */ 24810388SAndreas.Sandberg@ARM.com bool isIncoming() const { return !isOutgoing(); } 24910388SAndreas.Sandberg@ARM.com /** Check if this is a write-only descriptor (outgoing data). */ 25010388SAndreas.Sandberg@ARM.com bool isOutgoing() const { return desc.flags & VRING_DESC_F_WRITE; } 25110388SAndreas.Sandberg@ARM.com 25210388SAndreas.Sandberg@ARM.com 25310388SAndreas.Sandberg@ARM.com /** 25410388SAndreas.Sandberg@ARM.com * Read the contents of a descriptor chain. 25510388SAndreas.Sandberg@ARM.com * 25610388SAndreas.Sandberg@ARM.com * This method reads the specified number of bytes from a 25710388SAndreas.Sandberg@ARM.com * descriptor chain starting at the this descriptor plus an offset 25810388SAndreas.Sandberg@ARM.com * in bytes. The method automatically follows the links in the 25910388SAndreas.Sandberg@ARM.com * descriptor chain. 26010388SAndreas.Sandberg@ARM.com * 26110388SAndreas.Sandberg@ARM.com * @param offset Offset into the chain (in bytes). 26210388SAndreas.Sandberg@ARM.com * @param dst Pointer to destination buffer. 26310388SAndreas.Sandberg@ARM.com * @param size Size (in bytes). 26410388SAndreas.Sandberg@ARM.com */ 26510388SAndreas.Sandberg@ARM.com void chainRead(size_t offset, uint8_t *dst, size_t size) const; 26610388SAndreas.Sandberg@ARM.com /** 26710388SAndreas.Sandberg@ARM.com * Write to a descriptor chain. 26810388SAndreas.Sandberg@ARM.com * 26910388SAndreas.Sandberg@ARM.com * This method writes the specified number of bytes to a 27010388SAndreas.Sandberg@ARM.com * descriptor chain starting at the this descriptor plus an offset 27110388SAndreas.Sandberg@ARM.com * in bytes. The method automatically follows the links in the 27210388SAndreas.Sandberg@ARM.com * descriptor chain. 27310388SAndreas.Sandberg@ARM.com * 27410388SAndreas.Sandberg@ARM.com * @param offset Offset into the chain (in bytes). 27510388SAndreas.Sandberg@ARM.com * @param src Pointer to source buffer. 27610388SAndreas.Sandberg@ARM.com * @param size Size (in bytes). 27710388SAndreas.Sandberg@ARM.com */ 27810388SAndreas.Sandberg@ARM.com void chainWrite(size_t offset, const uint8_t *src, size_t size); 27910388SAndreas.Sandberg@ARM.com /** 28010388SAndreas.Sandberg@ARM.com * Retrieve the size of this descriptor chain. 28110388SAndreas.Sandberg@ARM.com * 28210388SAndreas.Sandberg@ARM.com * This method gets the size of a descriptor chain starting at 28310388SAndreas.Sandberg@ARM.com * this descriptor. 28410388SAndreas.Sandberg@ARM.com * 28510388SAndreas.Sandberg@ARM.com * @return Size of descriptor chain in bytes. 28610388SAndreas.Sandberg@ARM.com */ 28710388SAndreas.Sandberg@ARM.com size_t chainSize() const; 28810388SAndreas.Sandberg@ARM.com /** @} */ 28910388SAndreas.Sandberg@ARM.com 29010388SAndreas.Sandberg@ARM.com private: 29110388SAndreas.Sandberg@ARM.com // Remove default constructor 29210388SAndreas.Sandberg@ARM.com VirtDescriptor(); 29310388SAndreas.Sandberg@ARM.com // Prevent copying 29410388SAndreas.Sandberg@ARM.com VirtDescriptor(const VirtDescriptor &other); 29510388SAndreas.Sandberg@ARM.com 29610388SAndreas.Sandberg@ARM.com /** Pointer to memory proxy */ 29710388SAndreas.Sandberg@ARM.com PortProxy *memProxy; 29810388SAndreas.Sandberg@ARM.com /** Pointer to virtqueue owning this descriptor */ 29910388SAndreas.Sandberg@ARM.com VirtQueue *queue; 30010388SAndreas.Sandberg@ARM.com 30110388SAndreas.Sandberg@ARM.com /** Index in virtqueue */ 30210388SAndreas.Sandberg@ARM.com Index _index; 30310388SAndreas.Sandberg@ARM.com 30410388SAndreas.Sandberg@ARM.com /** Underlying descriptor */ 30510388SAndreas.Sandberg@ARM.com vring_desc desc; 30610388SAndreas.Sandberg@ARM.com}; 30710388SAndreas.Sandberg@ARM.com 30810388SAndreas.Sandberg@ARM.com/** 30910388SAndreas.Sandberg@ARM.com * Base wrapper around a virtqueue. 31010388SAndreas.Sandberg@ARM.com * 31110388SAndreas.Sandberg@ARM.com * VirtIO device models typically need to extend this class to 31210388SAndreas.Sandberg@ARM.com * implement their own device queues. 31310388SAndreas.Sandberg@ARM.com * 31410388SAndreas.Sandberg@ARM.com * @note Queues must be registered with 31510388SAndreas.Sandberg@ARM.com * VirtIODeviceBase::registerQueue() to be active. 31610388SAndreas.Sandberg@ARM.com */ 31710905Sandreas.sandberg@arm.comclass VirtQueue : public Serializable { 31810388SAndreas.Sandberg@ARM.compublic: 31910388SAndreas.Sandberg@ARM.com virtual ~VirtQueue() {}; 32010388SAndreas.Sandberg@ARM.com 32110388SAndreas.Sandberg@ARM.com /** @{ 32210388SAndreas.Sandberg@ARM.com * @name Checkpointing Interface 32310388SAndreas.Sandberg@ARM.com */ 32411168Sandreas.hansson@arm.com void serialize(CheckpointOut &cp) const override; 32511168Sandreas.hansson@arm.com void unserialize(CheckpointIn &cp) override; 32610388SAndreas.Sandberg@ARM.com 32710388SAndreas.Sandberg@ARM.com /** @{ 32810388SAndreas.Sandberg@ARM.com * @name Low-level Device Interface 32910388SAndreas.Sandberg@ARM.com */ 33010388SAndreas.Sandberg@ARM.com /** 33110388SAndreas.Sandberg@ARM.com * Set the base address of this queue. 33210388SAndreas.Sandberg@ARM.com * 33310388SAndreas.Sandberg@ARM.com * @param address Guest physical base address of the queue. 33410388SAndreas.Sandberg@ARM.com */ 33510388SAndreas.Sandberg@ARM.com void setAddress(Addr address); 33610388SAndreas.Sandberg@ARM.com /** 33710388SAndreas.Sandberg@ARM.com * Get the guest physical address of this queue. 33810388SAndreas.Sandberg@ARM.com * 33910388SAndreas.Sandberg@ARM.com * @return Physical address in guest where this queue resides. 34010388SAndreas.Sandberg@ARM.com */ 34110388SAndreas.Sandberg@ARM.com Addr getAddress() const { return _address; } 34210388SAndreas.Sandberg@ARM.com 34310388SAndreas.Sandberg@ARM.com /** 34410388SAndreas.Sandberg@ARM.com * Get the number of descriptors available in this queue. 34510388SAndreas.Sandberg@ARM.com * 34610388SAndreas.Sandberg@ARM.com * @return Size of queue in descriptors. 34710388SAndreas.Sandberg@ARM.com */ 34810388SAndreas.Sandberg@ARM.com uint16_t getSize() const { return _size; } 34910388SAndreas.Sandberg@ARM.com 35010388SAndreas.Sandberg@ARM.com /** 35110388SAndreas.Sandberg@ARM.com * Get a pointer to a specific descriptor in the queue. 35210388SAndreas.Sandberg@ARM.com * 35310388SAndreas.Sandberg@ARM.com * @note This interfaces is normally only used by VirtDescriptor 35410388SAndreas.Sandberg@ARM.com * to follow descriptor chains. Device models typically don't need 35510388SAndreas.Sandberg@ARM.com * to use it. 35610388SAndreas.Sandberg@ARM.com * 35710388SAndreas.Sandberg@ARM.com * @return Pointer to a VirtDescriptor. 35810388SAndreas.Sandberg@ARM.com */ 35910388SAndreas.Sandberg@ARM.com VirtDescriptor *getDescriptor(VirtDescriptor::Index index) { 36010388SAndreas.Sandberg@ARM.com return &descriptors[index]; 36110388SAndreas.Sandberg@ARM.com } 36210388SAndreas.Sandberg@ARM.com /** @} */ 36310388SAndreas.Sandberg@ARM.com 36410388SAndreas.Sandberg@ARM.com /** @{ 36510388SAndreas.Sandberg@ARM.com * @name Device Model Interfaces 36610388SAndreas.Sandberg@ARM.com */ 36710388SAndreas.Sandberg@ARM.com /** 36810388SAndreas.Sandberg@ARM.com * Get an incoming descriptor chain from the queue. 36910388SAndreas.Sandberg@ARM.com * 37010388SAndreas.Sandberg@ARM.com * @return Pointer to descriptor on success, NULL if no pending 37110388SAndreas.Sandberg@ARM.com * descriptors are available. 37210388SAndreas.Sandberg@ARM.com */ 37310388SAndreas.Sandberg@ARM.com VirtDescriptor *consumeDescriptor(); 37410388SAndreas.Sandberg@ARM.com /** 37510388SAndreas.Sandberg@ARM.com * Send a descriptor chain to the guest. 37610388SAndreas.Sandberg@ARM.com * 37710388SAndreas.Sandberg@ARM.com * This method posts a descriptor chain to the guest after a 37810388SAndreas.Sandberg@ARM.com * device model has finished processing it. The device model 37910388SAndreas.Sandberg@ARM.com * typically needs to call VirtIODeviceBase::kick() to deliver 38010388SAndreas.Sandberg@ARM.com * notify tell the guest that the queue has been updated. 38110388SAndreas.Sandberg@ARM.com * 38210388SAndreas.Sandberg@ARM.com * @note The desc parameter must refer to the first descriptor in 38310388SAndreas.Sandberg@ARM.com * a chain that has been retrieved using consumeDescriptor(). 38410388SAndreas.Sandberg@ARM.com * 38510388SAndreas.Sandberg@ARM.com * @note The len parameter specified the amount of data produced 38610388SAndreas.Sandberg@ARM.com * by the device model. It seems to be ignored by Linux and it is 38710388SAndreas.Sandberg@ARM.com * not well defined. 38810388SAndreas.Sandberg@ARM.com * 38910388SAndreas.Sandberg@ARM.com * @param desc Start of descriptor chain. 39010388SAndreas.Sandberg@ARM.com * @param len Length of the produced data. 39110388SAndreas.Sandberg@ARM.com */ 39210388SAndreas.Sandberg@ARM.com void produceDescriptor(VirtDescriptor *desc, uint32_t len); 39310388SAndreas.Sandberg@ARM.com /** @} */ 39410388SAndreas.Sandberg@ARM.com 39510388SAndreas.Sandberg@ARM.com /** @{ 39610388SAndreas.Sandberg@ARM.com * @name Device Model Callbacks 39710388SAndreas.Sandberg@ARM.com */ 39810388SAndreas.Sandberg@ARM.com /** 39910388SAndreas.Sandberg@ARM.com * Notify queue of pending events. 40010388SAndreas.Sandberg@ARM.com * 40110388SAndreas.Sandberg@ARM.com * This method is called by VirtIODeviceBase::onNotify() to notify 40210388SAndreas.Sandberg@ARM.com * the device model of pending data in a virtqueue. The default 40310388SAndreas.Sandberg@ARM.com * implementation of this method iterates over the available 40410388SAndreas.Sandberg@ARM.com * descriptor chains and calls onNotifyDescriptor() for every new 40510388SAndreas.Sandberg@ARM.com * incoming chain. 40610388SAndreas.Sandberg@ARM.com * 40710388SAndreas.Sandberg@ARM.com * Device models should normally overload one of onNotify() and 40810388SAndreas.Sandberg@ARM.com * onNotifyDescriptor(). 40910388SAndreas.Sandberg@ARM.com */ 41010388SAndreas.Sandberg@ARM.com virtual void onNotify(); 41110388SAndreas.Sandberg@ARM.com /** 41210388SAndreas.Sandberg@ARM.com * Notify queue of pending incoming descriptor. 41310388SAndreas.Sandberg@ARM.com * 41410388SAndreas.Sandberg@ARM.com * This method is called by the default implementation of 41510388SAndreas.Sandberg@ARM.com * onNotify() to notify the device model of pending data in a 41610388SAndreas.Sandberg@ARM.com * descriptor chain. 41710388SAndreas.Sandberg@ARM.com * 41810388SAndreas.Sandberg@ARM.com * Device models should normally overload one of onNotify() and 41910388SAndreas.Sandberg@ARM.com * onNotifyDescriptor(). 42010388SAndreas.Sandberg@ARM.com */ 42110388SAndreas.Sandberg@ARM.com virtual void onNotifyDescriptor(VirtDescriptor *desc) {}; 42210388SAndreas.Sandberg@ARM.com /** @} */ 42310388SAndreas.Sandberg@ARM.com 42410388SAndreas.Sandberg@ARM.com /** @{ 42510388SAndreas.Sandberg@ARM.com * @name Debug interfaces 42610388SAndreas.Sandberg@ARM.com */ 42710388SAndreas.Sandberg@ARM.com /** Dump the contents of a queue */ 42810388SAndreas.Sandberg@ARM.com void dump() const; 42910388SAndreas.Sandberg@ARM.com /** @} */ 43010388SAndreas.Sandberg@ARM.com 43110388SAndreas.Sandberg@ARM.com /** @{ */ 43210388SAndreas.Sandberg@ARM.com /** 43310388SAndreas.Sandberg@ARM.com * Page size used by VirtIO.\ It's hard-coded to 4096 bytes in 43410388SAndreas.Sandberg@ARM.com * the spec for historical reasons. 43510388SAndreas.Sandberg@ARM.com */ 43612114Ssascha.bischoff@arm.com static const Addr ALIGN_BITS = 12; 43712114Ssascha.bischoff@arm.com static const Addr ALIGN_SIZE = 1 << ALIGN_BITS; 43810388SAndreas.Sandberg@ARM.com /** @} */ 43910388SAndreas.Sandberg@ARM.com 44010388SAndreas.Sandberg@ARM.com protected: 44110388SAndreas.Sandberg@ARM.com /** 44210388SAndreas.Sandberg@ARM.com * Instantiate a new virtqueue. 44310388SAndreas.Sandberg@ARM.com * 44410388SAndreas.Sandberg@ARM.com * Instantiate a virtqueue with a fixed size. The size is 44510388SAndreas.Sandberg@ARM.com * specified in descriptors which are defined as 4096 bytes each. 44610388SAndreas.Sandberg@ARM.com * 44710388SAndreas.Sandberg@ARM.com * @param proxy Proxy to the guest physical memory. 44810388SAndreas.Sandberg@ARM.com * @param size Size in descriptors/pages. 44910388SAndreas.Sandberg@ARM.com */ 45010388SAndreas.Sandberg@ARM.com VirtQueue(PortProxy &proxy, uint16_t size); 45110388SAndreas.Sandberg@ARM.com 45210388SAndreas.Sandberg@ARM.com private: 45310388SAndreas.Sandberg@ARM.com VirtQueue(); 45410388SAndreas.Sandberg@ARM.com 45510388SAndreas.Sandberg@ARM.com /** Queue size in terms of number of descriptors */ 45610388SAndreas.Sandberg@ARM.com const uint16_t _size; 45710388SAndreas.Sandberg@ARM.com /** Base address of the queue */ 45810388SAndreas.Sandberg@ARM.com Addr _address; 45910388SAndreas.Sandberg@ARM.com /** Guest physical memory proxy */ 46010388SAndreas.Sandberg@ARM.com PortProxy &memProxy; 46110388SAndreas.Sandberg@ARM.com 46210388SAndreas.Sandberg@ARM.com private: 46310388SAndreas.Sandberg@ARM.com /** 46410388SAndreas.Sandberg@ARM.com * VirtIO ring buffer wrapper. 46510388SAndreas.Sandberg@ARM.com * 46610388SAndreas.Sandberg@ARM.com * This class wraps a VirtIO ring buffer. The template parameter T 46710388SAndreas.Sandberg@ARM.com * is used to select the data type for the items in the ring (used 46810388SAndreas.Sandberg@ARM.com * or available descriptors). 46910388SAndreas.Sandberg@ARM.com */ 47010388SAndreas.Sandberg@ARM.com template<typename T> 47110388SAndreas.Sandberg@ARM.com class VirtRing 47210388SAndreas.Sandberg@ARM.com { 47310388SAndreas.Sandberg@ARM.com public: 47410388SAndreas.Sandberg@ARM.com typedef uint16_t Flags; 47510388SAndreas.Sandberg@ARM.com typedef uint16_t Index; 47610388SAndreas.Sandberg@ARM.com 47710388SAndreas.Sandberg@ARM.com struct Header { 47810388SAndreas.Sandberg@ARM.com Flags flags; 47910388SAndreas.Sandberg@ARM.com Index index; 48010388SAndreas.Sandberg@ARM.com } M5_ATTR_PACKED; 48110388SAndreas.Sandberg@ARM.com 48210388SAndreas.Sandberg@ARM.com VirtRing<T>(PortProxy &proxy, uint16_t size) 48310559Sandreas.hansson@arm.com : header{0, 0}, ring(size), _proxy(proxy), _base(0) {} 48410388SAndreas.Sandberg@ARM.com 48510388SAndreas.Sandberg@ARM.com /** 48610388SAndreas.Sandberg@ARM.com * Set the base address of the VirtIO ring buffer. 48710388SAndreas.Sandberg@ARM.com * 48810388SAndreas.Sandberg@ARM.com * @param addr New host physical address 48910388SAndreas.Sandberg@ARM.com */ 49010388SAndreas.Sandberg@ARM.com void setAddress(Addr addr) { _base = addr; } 49110388SAndreas.Sandberg@ARM.com 49210388SAndreas.Sandberg@ARM.com /** Update the ring buffer header with data from the guest. */ 49310388SAndreas.Sandberg@ARM.com void readHeader() { 49410388SAndreas.Sandberg@ARM.com assert(_base != 0); 49514010Sgabeblack@google.com _proxy.readBlob(_base, &header, sizeof(header)); 49610388SAndreas.Sandberg@ARM.com header.flags = vtoh_legacy(header.flags); 49710388SAndreas.Sandberg@ARM.com header.index = vtoh_legacy(header.index); 49810388SAndreas.Sandberg@ARM.com } 49910388SAndreas.Sandberg@ARM.com 50010388SAndreas.Sandberg@ARM.com void writeHeader() { 50110388SAndreas.Sandberg@ARM.com Header out; 50210388SAndreas.Sandberg@ARM.com assert(_base != 0); 50310388SAndreas.Sandberg@ARM.com out.flags = htov_legacy(header.flags); 50410388SAndreas.Sandberg@ARM.com out.index = htov_legacy(header.index); 50514010Sgabeblack@google.com _proxy.writeBlob(_base, &out, sizeof(out)); 50610388SAndreas.Sandberg@ARM.com } 50710388SAndreas.Sandberg@ARM.com 50810388SAndreas.Sandberg@ARM.com void read() { 50910388SAndreas.Sandberg@ARM.com readHeader(); 51010388SAndreas.Sandberg@ARM.com 51110388SAndreas.Sandberg@ARM.com /* Read and byte-swap the elements in the ring */ 51210388SAndreas.Sandberg@ARM.com T temp[ring.size()]; 51310388SAndreas.Sandberg@ARM.com _proxy.readBlob(_base + sizeof(header), 51414010Sgabeblack@google.com temp, sizeof(T) * ring.size()); 51510388SAndreas.Sandberg@ARM.com for (int i = 0; i < ring.size(); ++i) 51610388SAndreas.Sandberg@ARM.com ring[i] = vtoh_legacy(temp[i]); 51710388SAndreas.Sandberg@ARM.com } 51810388SAndreas.Sandberg@ARM.com 51910388SAndreas.Sandberg@ARM.com void write() { 52010388SAndreas.Sandberg@ARM.com assert(_base != 0); 52110388SAndreas.Sandberg@ARM.com /* Create a byte-swapped copy of the ring and write it to 52210388SAndreas.Sandberg@ARM.com * guest memory. */ 52310388SAndreas.Sandberg@ARM.com T temp[ring.size()]; 52410388SAndreas.Sandberg@ARM.com for (int i = 0; i < ring.size(); ++i) 52510388SAndreas.Sandberg@ARM.com temp[i] = htov_legacy(ring[i]); 52610388SAndreas.Sandberg@ARM.com _proxy.writeBlob(_base + sizeof(header), 52714010Sgabeblack@google.com temp, sizeof(T) * ring.size()); 52810388SAndreas.Sandberg@ARM.com writeHeader(); 52910388SAndreas.Sandberg@ARM.com } 53010388SAndreas.Sandberg@ARM.com 53110388SAndreas.Sandberg@ARM.com /** Ring buffer header in host byte order */ 53210388SAndreas.Sandberg@ARM.com Header header; 53310388SAndreas.Sandberg@ARM.com /** Elements in ring in host byte order */ 53410388SAndreas.Sandberg@ARM.com std::vector<T> ring; 53510388SAndreas.Sandberg@ARM.com 53610388SAndreas.Sandberg@ARM.com private: 53710388SAndreas.Sandberg@ARM.com // Remove default constructor 53810388SAndreas.Sandberg@ARM.com VirtRing<T>(); 53910388SAndreas.Sandberg@ARM.com 54010388SAndreas.Sandberg@ARM.com /** Guest physical memory proxy */ 54110388SAndreas.Sandberg@ARM.com PortProxy &_proxy; 54210388SAndreas.Sandberg@ARM.com /** Guest physical base address of the ring buffer */ 54310388SAndreas.Sandberg@ARM.com Addr _base; 54410388SAndreas.Sandberg@ARM.com }; 54510388SAndreas.Sandberg@ARM.com 54610388SAndreas.Sandberg@ARM.com /** Ring of available (incoming) descriptors */ 54710388SAndreas.Sandberg@ARM.com VirtRing<VirtDescriptor::Index> avail; 54810388SAndreas.Sandberg@ARM.com /** Ring of used (outgoing) descriptors */ 54910388SAndreas.Sandberg@ARM.com VirtRing<struct vring_used_elem> used; 55010388SAndreas.Sandberg@ARM.com 55110388SAndreas.Sandberg@ARM.com /** Offset of last consumed descriptor in the VirtQueue::avail 55210388SAndreas.Sandberg@ARM.com * ring */ 55310388SAndreas.Sandberg@ARM.com uint16_t _last_avail; 55410388SAndreas.Sandberg@ARM.com 55510388SAndreas.Sandberg@ARM.com /** Vector of pre-created descriptors indexed by their index into 55610388SAndreas.Sandberg@ARM.com * the queue. */ 55710388SAndreas.Sandberg@ARM.com std::vector<VirtDescriptor> descriptors; 55810388SAndreas.Sandberg@ARM.com}; 55910388SAndreas.Sandberg@ARM.com 56010388SAndreas.Sandberg@ARM.com/** 56110388SAndreas.Sandberg@ARM.com * Base class for all VirtIO-based devices. 56210388SAndreas.Sandberg@ARM.com * 56310388SAndreas.Sandberg@ARM.com * This class implements the functionality of the VirtIO 0.9.5 56410388SAndreas.Sandberg@ARM.com * specification. This version of VirtIO is also known as "legacy" in 56510388SAndreas.Sandberg@ARM.com * the VirtIO 1.0 specification from OASIS. 56610388SAndreas.Sandberg@ARM.com * 56710388SAndreas.Sandberg@ARM.com * @see https://github.com/rustyrussell/virtio-spec 56810388SAndreas.Sandberg@ARM.com * @see http://docs.oasis-open.org/virtio/virtio/v1.0/virtio-v1.0.html 56910388SAndreas.Sandberg@ARM.com */ 57010388SAndreas.Sandberg@ARM.comclass VirtIODeviceBase : public SimObject 57110388SAndreas.Sandberg@ARM.com{ 57210388SAndreas.Sandberg@ARM.com public: 57310388SAndreas.Sandberg@ARM.com typedef uint16_t QueueID; 57410388SAndreas.Sandberg@ARM.com typedef uint32_t FeatureBits; 57510388SAndreas.Sandberg@ARM.com /** This is a VirtQueue address as exposed through the low-level 57610388SAndreas.Sandberg@ARM.com * interface.\ The address needs to be multiplied by the page size 57710388SAndreas.Sandberg@ARM.com * (seems to be hardcoded to 4096 in the spec) to get the real 57810388SAndreas.Sandberg@ARM.com * physical address. 57910388SAndreas.Sandberg@ARM.com */ 58010388SAndreas.Sandberg@ARM.com typedef uint16_t VirtAddress; 58110388SAndreas.Sandberg@ARM.com /** Device Type (sometimes known as subsystem ID) */ 58210388SAndreas.Sandberg@ARM.com typedef uint16_t DeviceId; 58310388SAndreas.Sandberg@ARM.com 58410388SAndreas.Sandberg@ARM.com BitUnion8(DeviceStatus) 58510388SAndreas.Sandberg@ARM.com Bitfield<7> failed; 58610388SAndreas.Sandberg@ARM.com Bitfield<2> driver_ok; 58710388SAndreas.Sandberg@ARM.com Bitfield<1> driver; 58810388SAndreas.Sandberg@ARM.com Bitfield<0> acknowledge; 58910388SAndreas.Sandberg@ARM.com EndBitUnion(DeviceStatus) 59010388SAndreas.Sandberg@ARM.com 59110388SAndreas.Sandberg@ARM.com typedef VirtIODeviceBaseParams Params; 59210388SAndreas.Sandberg@ARM.com VirtIODeviceBase(Params *params, DeviceId id, size_t config_size, 59310388SAndreas.Sandberg@ARM.com FeatureBits features); 59410388SAndreas.Sandberg@ARM.com virtual ~VirtIODeviceBase(); 59510388SAndreas.Sandberg@ARM.com 59610388SAndreas.Sandberg@ARM.com public: 59710388SAndreas.Sandberg@ARM.com /** @{ 59810388SAndreas.Sandberg@ARM.com * @name SimObject Interfaces 59910388SAndreas.Sandberg@ARM.com */ 60011168Sandreas.hansson@arm.com void serialize(CheckpointOut &cp) const override; 60111168Sandreas.hansson@arm.com void unserialize(CheckpointIn &cp) override; 60210388SAndreas.Sandberg@ARM.com /** @} */ 60310388SAndreas.Sandberg@ARM.com 60410388SAndreas.Sandberg@ARM.com 60510388SAndreas.Sandberg@ARM.com protected: 60610388SAndreas.Sandberg@ARM.com /** @{ 60710388SAndreas.Sandberg@ARM.com * @name Device Model Interfaces 60810388SAndreas.Sandberg@ARM.com */ 60910388SAndreas.Sandberg@ARM.com 61010388SAndreas.Sandberg@ARM.com /** 61110388SAndreas.Sandberg@ARM.com * Inform the guest of available buffers. 61210388SAndreas.Sandberg@ARM.com * 61310388SAndreas.Sandberg@ARM.com * When a device model has finished processing incoming buffers 61410388SAndreas.Sandberg@ARM.com * (after onNotify has been called), it typically needs to inform 61510388SAndreas.Sandberg@ARM.com * the guest that there are new pending outgoing buffers. The 61610388SAndreas.Sandberg@ARM.com * method used to inform the guest is transport dependent, but is 61710388SAndreas.Sandberg@ARM.com * typically through an interrupt. Device models call this method 61810388SAndreas.Sandberg@ARM.com * to tell the transport interface to notify the guest. 61910388SAndreas.Sandberg@ARM.com */ 62010388SAndreas.Sandberg@ARM.com void kick() { 62110388SAndreas.Sandberg@ARM.com assert(transKick); 62210388SAndreas.Sandberg@ARM.com transKick->process(); 62310388SAndreas.Sandberg@ARM.com }; 62410388SAndreas.Sandberg@ARM.com 62510388SAndreas.Sandberg@ARM.com /** 62610388SAndreas.Sandberg@ARM.com * Register a new VirtQueue with the device model. 62710388SAndreas.Sandberg@ARM.com * 62810388SAndreas.Sandberg@ARM.com * Devices typically register at least one VirtQueue to use for 62910388SAndreas.Sandberg@ARM.com * communication with the guest. This <i>must</i> be done from the 63010388SAndreas.Sandberg@ARM.com * constructor since the number of queues are assumed to be 63110388SAndreas.Sandberg@ARM.com * constant throughout the lifetime of the device. 63210388SAndreas.Sandberg@ARM.com * 63310388SAndreas.Sandberg@ARM.com * @warning This method may only be called from the device model 63410388SAndreas.Sandberg@ARM.com * constructor. 63510388SAndreas.Sandberg@ARM.com */ 63610388SAndreas.Sandberg@ARM.com void registerQueue(VirtQueue &queue); 63710388SAndreas.Sandberg@ARM.com 63810388SAndreas.Sandberg@ARM.com 63910388SAndreas.Sandberg@ARM.com /** 64010388SAndreas.Sandberg@ARM.com * Feature set accepted by the guest. 64110388SAndreas.Sandberg@ARM.com * 64210388SAndreas.Sandberg@ARM.com * When the guest starts the driver for the device, it starts by 64310388SAndreas.Sandberg@ARM.com * negotiating features. The device first offers a set of features 64410388SAndreas.Sandberg@ARM.com * (see deviceFeatures), the driver then notifies the device of 64510388SAndreas.Sandberg@ARM.com * which features it accepted. The base class will automatically 64610388SAndreas.Sandberg@ARM.com * accept any feature set that is a subset of the features offered 64710388SAndreas.Sandberg@ARM.com * by the device. 64810388SAndreas.Sandberg@ARM.com */ 64910388SAndreas.Sandberg@ARM.com FeatureBits guestFeatures; 65010388SAndreas.Sandberg@ARM.com /** @} */ 65110388SAndreas.Sandberg@ARM.com 65210388SAndreas.Sandberg@ARM.com public: 65310388SAndreas.Sandberg@ARM.com /** @{ 65410388SAndreas.Sandberg@ARM.com * @name Optional VirtIO Interfaces 65510388SAndreas.Sandberg@ARM.com */ 65610388SAndreas.Sandberg@ARM.com /** 65710388SAndreas.Sandberg@ARM.com * Read from the configuration space of a device. 65810388SAndreas.Sandberg@ARM.com * 65910388SAndreas.Sandberg@ARM.com * This method is called by the transport interface to read data 66010388SAndreas.Sandberg@ARM.com * from a device model's configuration space. The device model 66110388SAndreas.Sandberg@ARM.com * should use the cfgOffset parameter as the offset into its 66210388SAndreas.Sandberg@ARM.com * configuration space. 66310388SAndreas.Sandberg@ARM.com * 66410388SAndreas.Sandberg@ARM.com * @warning The address in the packet should not be used to 66510388SAndreas.Sandberg@ARM.com * determine the offset into a device's configuration space. 66610388SAndreas.Sandberg@ARM.com * 66710388SAndreas.Sandberg@ARM.com * @param pkt Read request packet. 66810388SAndreas.Sandberg@ARM.com * @param cfgOffset Offset into the device's configuration space. 66910388SAndreas.Sandberg@ARM.com */ 67010388SAndreas.Sandberg@ARM.com virtual void readConfig(PacketPtr pkt, Addr cfgOffset); 67110388SAndreas.Sandberg@ARM.com /** 67210388SAndreas.Sandberg@ARM.com * Write to the configuration space of a device. 67310388SAndreas.Sandberg@ARM.com * 67410388SAndreas.Sandberg@ARM.com * This method is called by the transport interface to write data 67510388SAndreas.Sandberg@ARM.com * into a device model's configuration space. The device model 67610388SAndreas.Sandberg@ARM.com * should use the cfgOffset parameter as the offset into its 67710388SAndreas.Sandberg@ARM.com * configuration space. 67810388SAndreas.Sandberg@ARM.com * 67910388SAndreas.Sandberg@ARM.com * @warning The address in the packet should not be used to 68010388SAndreas.Sandberg@ARM.com * determine the offset into a device's configuration space. 68110388SAndreas.Sandberg@ARM.com * 68210388SAndreas.Sandberg@ARM.com * @param pkt Write request packet. 68310388SAndreas.Sandberg@ARM.com * @param cfgOffset Offset into the device's configuration space. 68410388SAndreas.Sandberg@ARM.com */ 68510388SAndreas.Sandberg@ARM.com virtual void writeConfig(PacketPtr pkt, Addr cfgOffset); 68610388SAndreas.Sandberg@ARM.com 68710388SAndreas.Sandberg@ARM.com /** 68810388SAndreas.Sandberg@ARM.com * Driver-request device reset. 68910388SAndreas.Sandberg@ARM.com * 69010388SAndreas.Sandberg@ARM.com * The device driver may reset a device by writing zero to the 69110388SAndreas.Sandberg@ARM.com * device status register (using setDeviceStatus()), which causes 69210388SAndreas.Sandberg@ARM.com * this method to be called. Device models overriding this method 69310388SAndreas.Sandberg@ARM.com * <i>must</i> ensure that the reset method of the base class is 69410388SAndreas.Sandberg@ARM.com * called when the device is reset. 69510388SAndreas.Sandberg@ARM.com * 69610388SAndreas.Sandberg@ARM.com * @note Always call the reset method of the base class from 69710388SAndreas.Sandberg@ARM.com * device-specific reset methods. 69810388SAndreas.Sandberg@ARM.com */ 69910388SAndreas.Sandberg@ARM.com virtual void reset(); 70010388SAndreas.Sandberg@ARM.com /** @} */ 70110388SAndreas.Sandberg@ARM.com 70210388SAndreas.Sandberg@ARM.com protected: 70310388SAndreas.Sandberg@ARM.com /** @{ 70410388SAndreas.Sandberg@ARM.com * @name Device Model Helpers 70510388SAndreas.Sandberg@ARM.com */ 70610388SAndreas.Sandberg@ARM.com 70710388SAndreas.Sandberg@ARM.com /** 70810388SAndreas.Sandberg@ARM.com * Read configuration data from a device structure. 70910388SAndreas.Sandberg@ARM.com * 71010388SAndreas.Sandberg@ARM.com * @param pkt Read request packet. 71110388SAndreas.Sandberg@ARM.com * @param cfgOffset Offset into the device's configuration space. 71210388SAndreas.Sandberg@ARM.com * @param cfg Device configuration 71310388SAndreas.Sandberg@ARM.com */ 71410388SAndreas.Sandberg@ARM.com void readConfigBlob(PacketPtr pkt, Addr cfgOffset, const uint8_t *cfg); 71510388SAndreas.Sandberg@ARM.com 71610388SAndreas.Sandberg@ARM.com /** 71710388SAndreas.Sandberg@ARM.com * Write configuration data to a device structure. 71810388SAndreas.Sandberg@ARM.com * 71910388SAndreas.Sandberg@ARM.com * @param pkt Write request packet. 72010388SAndreas.Sandberg@ARM.com * @param cfgOffset Offset into the device's configuration space. 72110388SAndreas.Sandberg@ARM.com * @param cfg Device configuration 72210388SAndreas.Sandberg@ARM.com */ 72310388SAndreas.Sandberg@ARM.com void writeConfigBlob(PacketPtr pkt, Addr cfgOffset, uint8_t *cfg); 72410388SAndreas.Sandberg@ARM.com 72510388SAndreas.Sandberg@ARM.com /** @} */ 72610388SAndreas.Sandberg@ARM.com 72710388SAndreas.Sandberg@ARM.com public: 72810388SAndreas.Sandberg@ARM.com /** @{ 72910388SAndreas.Sandberg@ARM.com * @name VirtIO Transport Interfaces 73010388SAndreas.Sandberg@ARM.com */ 73110388SAndreas.Sandberg@ARM.com /** 73210388SAndreas.Sandberg@ARM.com * Register a callback to kick the guest through the transport 73310388SAndreas.Sandberg@ARM.com * interface. 73410388SAndreas.Sandberg@ARM.com * 73510388SAndreas.Sandberg@ARM.com * @param c Callback into transport interface. 73610388SAndreas.Sandberg@ARM.com */ 73710388SAndreas.Sandberg@ARM.com void registerKickCallback(Callback *c) { 73810388SAndreas.Sandberg@ARM.com assert(!transKick); 73910388SAndreas.Sandberg@ARM.com transKick = c; 74010388SAndreas.Sandberg@ARM.com } 74110388SAndreas.Sandberg@ARM.com 74210388SAndreas.Sandberg@ARM.com 74310388SAndreas.Sandberg@ARM.com /** 74410388SAndreas.Sandberg@ARM.com * Driver is requesting service. 74510388SAndreas.Sandberg@ARM.com * 74610388SAndreas.Sandberg@ARM.com * This method is called by the underlying hardware interface 74710388SAndreas.Sandberg@ARM.com * (e.g., PciVirtIO or MmmioVirtIO) to notify a device of pending 74810388SAndreas.Sandberg@ARM.com * incoming descriptors. 74910388SAndreas.Sandberg@ARM.com * 75010388SAndreas.Sandberg@ARM.com * @param index ID of the queue with pending actions. 75110388SAndreas.Sandberg@ARM.com */ 75210388SAndreas.Sandberg@ARM.com void onNotify(QueueID index); 75310388SAndreas.Sandberg@ARM.com 75410388SAndreas.Sandberg@ARM.com 75510388SAndreas.Sandberg@ARM.com /** 75610388SAndreas.Sandberg@ARM.com * Change currently active queue. 75710388SAndreas.Sandberg@ARM.com * 75810388SAndreas.Sandberg@ARM.com * The transport interface works on a queue at a time. The 75910388SAndreas.Sandberg@ARM.com * currently active queue is decided by the value of the queue 76010388SAndreas.Sandberg@ARM.com * select field in a device. 76110388SAndreas.Sandberg@ARM.com * 76210388SAndreas.Sandberg@ARM.com * @param idx ID of the queue to select. 76310388SAndreas.Sandberg@ARM.com */ 76410388SAndreas.Sandberg@ARM.com void setQueueSelect(QueueID idx) { _queueSelect = idx; } 76510388SAndreas.Sandberg@ARM.com /** 76610388SAndreas.Sandberg@ARM.com * Get the currently active queue. 76710388SAndreas.Sandberg@ARM.com * 76810388SAndreas.Sandberg@ARM.com * The transport interface works on a queue at a time. The 76910388SAndreas.Sandberg@ARM.com * currently active queue is decided by the value of the queue 77010388SAndreas.Sandberg@ARM.com * select field in a device. 77110388SAndreas.Sandberg@ARM.com * 77210388SAndreas.Sandberg@ARM.com * @return The ID of the currently active queue. 77310388SAndreas.Sandberg@ARM.com */ 77410388SAndreas.Sandberg@ARM.com QueueID getQueueSelect() const { return _queueSelect; } 77510388SAndreas.Sandberg@ARM.com 77610388SAndreas.Sandberg@ARM.com /** 77710388SAndreas.Sandberg@ARM.com * Change the host physical address of the currently active queue. 77810388SAndreas.Sandberg@ARM.com * 77910388SAndreas.Sandberg@ARM.com * @note The new address is specified in multiples of the page 78010388SAndreas.Sandberg@ARM.com * size (fixed to 4096 bytes in the standard). For example, if the 78110388SAndreas.Sandberg@ARM.com * address 10 is selected, the actual host physical address will 78210388SAndreas.Sandberg@ARM.com * be 40960. 78310388SAndreas.Sandberg@ARM.com * 78410388SAndreas.Sandberg@ARM.com * @see setQueueSelect 78510388SAndreas.Sandberg@ARM.com * @see getQueueSelect 78610388SAndreas.Sandberg@ARM.com * 78710388SAndreas.Sandberg@ARM.com * @param address New address of the currently active queue (in 78810388SAndreas.Sandberg@ARM.com * pages). 78910388SAndreas.Sandberg@ARM.com */ 79010388SAndreas.Sandberg@ARM.com void setQueueAddress(uint32_t address); 79110388SAndreas.Sandberg@ARM.com /** 79210388SAndreas.Sandberg@ARM.com * Get the host physical address of the currently active queue. 79310388SAndreas.Sandberg@ARM.com * 79410388SAndreas.Sandberg@ARM.com * @note The new address is specified in multiples of the page 79510388SAndreas.Sandberg@ARM.com * size (fixed to 4096 bytes in the standard). For example, if the 79610388SAndreas.Sandberg@ARM.com * address 10 is selected, the actual host physical address will 79710388SAndreas.Sandberg@ARM.com * be 40960. 79810388SAndreas.Sandberg@ARM.com * 79910388SAndreas.Sandberg@ARM.com * @see setQueueSelect 80010388SAndreas.Sandberg@ARM.com * @see getQueueSelect 80110388SAndreas.Sandberg@ARM.com * 80210388SAndreas.Sandberg@ARM.com * @return Address of the currently active queue (in pages). 80310388SAndreas.Sandberg@ARM.com */ 80410388SAndreas.Sandberg@ARM.com uint32_t getQueueAddress() const; 80510388SAndreas.Sandberg@ARM.com 80610388SAndreas.Sandberg@ARM.com /** 80710388SAndreas.Sandberg@ARM.com * Get the size (descriptors) of the currently active queue. 80810388SAndreas.Sandberg@ARM.com * 80910388SAndreas.Sandberg@ARM.com * @return Size of the currently active queue in number of 81010388SAndreas.Sandberg@ARM.com * descriptors. 81110388SAndreas.Sandberg@ARM.com */ 81210388SAndreas.Sandberg@ARM.com uint16_t getQueueSize() const { return getCurrentQueue().getSize(); } 81310388SAndreas.Sandberg@ARM.com 81410388SAndreas.Sandberg@ARM.com /** 81510388SAndreas.Sandberg@ARM.com * Update device status and optionally reset device. 81610388SAndreas.Sandberg@ARM.com * 81710388SAndreas.Sandberg@ARM.com * The special device status of 0 is used to reset the device by 81810388SAndreas.Sandberg@ARM.com * calling reset(). 81910388SAndreas.Sandberg@ARM.com * 82010388SAndreas.Sandberg@ARM.com * @param status New device status. 82110388SAndreas.Sandberg@ARM.com */ 82210388SAndreas.Sandberg@ARM.com void setDeviceStatus(DeviceStatus status); 82310388SAndreas.Sandberg@ARM.com 82410388SAndreas.Sandberg@ARM.com /** 82510388SAndreas.Sandberg@ARM.com * Retrieve the device status. 82610388SAndreas.Sandberg@ARM.com * 82710388SAndreas.Sandberg@ARM.com * @return Device status. 82810388SAndreas.Sandberg@ARM.com */ 82910388SAndreas.Sandberg@ARM.com DeviceStatus getDeviceStatus() const { return _deviceStatus; } 83010388SAndreas.Sandberg@ARM.com 83110388SAndreas.Sandberg@ARM.com /** 83210388SAndreas.Sandberg@ARM.com * Set feature bits accepted by the guest driver. 83310388SAndreas.Sandberg@ARM.com * 83410388SAndreas.Sandberg@ARM.com * This enables a subset of the features offered by the device 83510388SAndreas.Sandberg@ARM.com * model through the getGuestFeatures() interface. 83610388SAndreas.Sandberg@ARM.com */ 83710388SAndreas.Sandberg@ARM.com void setGuestFeatures(FeatureBits features); 83810388SAndreas.Sandberg@ARM.com 83910388SAndreas.Sandberg@ARM.com /** 84010388SAndreas.Sandberg@ARM.com * Get features accepted by the guest driver. 84110388SAndreas.Sandberg@ARM.com * 84210388SAndreas.Sandberg@ARM.com * @return Currently active features. 84310388SAndreas.Sandberg@ARM.com */ 84410388SAndreas.Sandberg@ARM.com FeatureBits getGuestFeatures() const { return guestFeatures; } 84510388SAndreas.Sandberg@ARM.com 84610388SAndreas.Sandberg@ARM.com /** Device ID (sometimes known as subsystem ID) */ 84710388SAndreas.Sandberg@ARM.com const DeviceId deviceId; 84810388SAndreas.Sandberg@ARM.com 84910388SAndreas.Sandberg@ARM.com /** Size of the device's configuration space */ 85010388SAndreas.Sandberg@ARM.com const size_t configSize; 85110388SAndreas.Sandberg@ARM.com 85210388SAndreas.Sandberg@ARM.com /** Feature set offered by the device */ 85310388SAndreas.Sandberg@ARM.com const FeatureBits deviceFeatures; 85410388SAndreas.Sandberg@ARM.com /** @} */ 85510388SAndreas.Sandberg@ARM.com 85610388SAndreas.Sandberg@ARM.com private: 85710388SAndreas.Sandberg@ARM.com /** Convenience method to get the currently selected queue */ 85810388SAndreas.Sandberg@ARM.com const VirtQueue &getCurrentQueue() const; 85910388SAndreas.Sandberg@ARM.com /** Convenience method to get the currently selected queue */ 86010388SAndreas.Sandberg@ARM.com VirtQueue &getCurrentQueue(); 86110388SAndreas.Sandberg@ARM.com 86210388SAndreas.Sandberg@ARM.com /** 86310388SAndreas.Sandberg@ARM.com * Status of the device 86410388SAndreas.Sandberg@ARM.com * 86510388SAndreas.Sandberg@ARM.com * @see getDeviceStatus 86610388SAndreas.Sandberg@ARM.com * @see setDeviceStatus 86710388SAndreas.Sandberg@ARM.com */ 86810388SAndreas.Sandberg@ARM.com DeviceStatus _deviceStatus; 86910388SAndreas.Sandberg@ARM.com 87010388SAndreas.Sandberg@ARM.com /** Queue select register (set by guest) */ 87110388SAndreas.Sandberg@ARM.com QueueID _queueSelect; 87210388SAndreas.Sandberg@ARM.com 87310388SAndreas.Sandberg@ARM.com /** List of virtual queues supported by this device */ 87410388SAndreas.Sandberg@ARM.com std::vector<VirtQueue *> _queues; 87510388SAndreas.Sandberg@ARM.com 87610388SAndreas.Sandberg@ARM.com /** Callbacks to kick the guest through the transport layer */ 87710388SAndreas.Sandberg@ARM.com Callback *transKick; 87810388SAndreas.Sandberg@ARM.com}; 87910388SAndreas.Sandberg@ARM.com 88011931Sandreas.sandberg@arm.comclass VirtIODummyDevice : public VirtIODeviceBase 88111931Sandreas.sandberg@arm.com{ 88211931Sandreas.sandberg@arm.com public: 88311931Sandreas.sandberg@arm.com VirtIODummyDevice(VirtIODummyDeviceParams *params); 88411931Sandreas.sandberg@arm.com 88511931Sandreas.sandberg@arm.com protected: 88611931Sandreas.sandberg@arm.com /** VirtIO device ID */ 88711931Sandreas.sandberg@arm.com static const DeviceId ID_INVALID = 0x00; 88811931Sandreas.sandberg@arm.com}; 88911931Sandreas.sandberg@arm.com 89010388SAndreas.Sandberg@ARM.com#endif // __DEV_VIRTIO_BASE_HH__ 891