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