110388SAndreas.Sandberg@ARM.com/* 211931Sandreas.sandberg@arm.com * Copyright (c) 2014, 2016 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 4011793Sbrandon.potter@amd.com#include "dev/virtio/base.hh" 4111793Sbrandon.potter@amd.com 4210388SAndreas.Sandberg@ARM.com#include "debug/VIO.hh" 4310388SAndreas.Sandberg@ARM.com#include "params/VirtIODeviceBase.hh" 4411931Sandreas.sandberg@arm.com#include "params/VirtIODummyDevice.hh" 4510388SAndreas.Sandberg@ARM.com 4610388SAndreas.Sandberg@ARM.comVirtDescriptor::VirtDescriptor(PortProxy &_memProxy, VirtQueue &_queue, 4710388SAndreas.Sandberg@ARM.com Index descIndex) 4810559Sandreas.hansson@arm.com : memProxy(&_memProxy), queue(&_queue), _index(descIndex), 4910559Sandreas.hansson@arm.com desc{0, 0, 0, 0} 5010388SAndreas.Sandberg@ARM.com{ 5110388SAndreas.Sandberg@ARM.com} 5210388SAndreas.Sandberg@ARM.com 5310388SAndreas.Sandberg@ARM.comVirtDescriptor::VirtDescriptor(VirtDescriptor &&other) noexcept 5410388SAndreas.Sandberg@ARM.com{ 5510388SAndreas.Sandberg@ARM.com *this = std::forward<VirtDescriptor>(other); 5610388SAndreas.Sandberg@ARM.com} 5710388SAndreas.Sandberg@ARM.com 5810388SAndreas.Sandberg@ARM.comVirtDescriptor::~VirtDescriptor() noexcept 5910388SAndreas.Sandberg@ARM.com{ 6010388SAndreas.Sandberg@ARM.com} 6110388SAndreas.Sandberg@ARM.com 6210388SAndreas.Sandberg@ARM.comVirtDescriptor & 6310388SAndreas.Sandberg@ARM.comVirtDescriptor::operator=(VirtDescriptor &&rhs) noexcept 6410388SAndreas.Sandberg@ARM.com{ 6510388SAndreas.Sandberg@ARM.com memProxy = std::move(rhs.memProxy); 6610388SAndreas.Sandberg@ARM.com queue = std::move(rhs.queue); 6710388SAndreas.Sandberg@ARM.com _index = std::move(rhs._index); 6810388SAndreas.Sandberg@ARM.com desc = std::move(rhs.desc); 6910388SAndreas.Sandberg@ARM.com 7010388SAndreas.Sandberg@ARM.com return *this; 7110388SAndreas.Sandberg@ARM.com} 7210388SAndreas.Sandberg@ARM.com 7310388SAndreas.Sandberg@ARM.comvoid 7410388SAndreas.Sandberg@ARM.comVirtDescriptor::update() 7510388SAndreas.Sandberg@ARM.com{ 7610388SAndreas.Sandberg@ARM.com const Addr vq_addr(queue->getAddress()); 7710388SAndreas.Sandberg@ARM.com // Check if the queue has been initialized yet 7810388SAndreas.Sandberg@ARM.com if (vq_addr == 0) 7910388SAndreas.Sandberg@ARM.com return; 8010388SAndreas.Sandberg@ARM.com 8110388SAndreas.Sandberg@ARM.com assert(_index < queue->getSize()); 8210388SAndreas.Sandberg@ARM.com const Addr desc_addr(vq_addr + sizeof(desc) * _index); 8310388SAndreas.Sandberg@ARM.com vring_desc guest_desc; 8414010Sgabeblack@google.com memProxy->readBlob(desc_addr, &guest_desc, sizeof(guest_desc)); 8510388SAndreas.Sandberg@ARM.com desc = vtoh_legacy(guest_desc); 8610388SAndreas.Sandberg@ARM.com DPRINTF(VIO, 8710388SAndreas.Sandberg@ARM.com "VirtDescriptor(%i): Addr: 0x%x, Len: %i, Flags: 0x%x, " 8810388SAndreas.Sandberg@ARM.com "Next: 0x%x\n", 8910388SAndreas.Sandberg@ARM.com _index, desc.addr, desc.len, desc.flags, desc.next); 9010388SAndreas.Sandberg@ARM.com} 9110388SAndreas.Sandberg@ARM.com 9210388SAndreas.Sandberg@ARM.comvoid 9310388SAndreas.Sandberg@ARM.comVirtDescriptor::updateChain() 9410388SAndreas.Sandberg@ARM.com{ 9510388SAndreas.Sandberg@ARM.com VirtDescriptor *desc(this); 9610388SAndreas.Sandberg@ARM.com do { 9710388SAndreas.Sandberg@ARM.com desc->update(); 9811321Ssteve.reinhardt@amd.com } while ((desc = desc->next()) != NULL && desc != this); 9910388SAndreas.Sandberg@ARM.com 10010388SAndreas.Sandberg@ARM.com if (desc == this) 10110388SAndreas.Sandberg@ARM.com panic("Loop in descriptor chain!\n"); 10210388SAndreas.Sandberg@ARM.com} 10310388SAndreas.Sandberg@ARM.com 10410388SAndreas.Sandberg@ARM.comvoid 10510388SAndreas.Sandberg@ARM.comVirtDescriptor::dump() const 10610388SAndreas.Sandberg@ARM.com{ 10710388SAndreas.Sandberg@ARM.com if (!DTRACE(VIO)) 10810388SAndreas.Sandberg@ARM.com return; 10910388SAndreas.Sandberg@ARM.com 11010388SAndreas.Sandberg@ARM.com DPRINTF(VIO, "Descriptor[%i]: " 11110388SAndreas.Sandberg@ARM.com "Addr: 0x%x, Len: %i, Flags: 0x%x, Next: 0x%x\n", 11210388SAndreas.Sandberg@ARM.com _index, desc.addr, desc.len, desc.flags, desc.next); 11310388SAndreas.Sandberg@ARM.com 11410388SAndreas.Sandberg@ARM.com if (isIncoming()) { 11510388SAndreas.Sandberg@ARM.com uint8_t data[desc.len]; 11610388SAndreas.Sandberg@ARM.com read(0, data, desc.len); 11710388SAndreas.Sandberg@ARM.com DDUMP(VIO, data, desc.len); 11810388SAndreas.Sandberg@ARM.com } 11910388SAndreas.Sandberg@ARM.com} 12010388SAndreas.Sandberg@ARM.com 12110388SAndreas.Sandberg@ARM.comvoid 12210388SAndreas.Sandberg@ARM.comVirtDescriptor::dumpChain() const 12310388SAndreas.Sandberg@ARM.com{ 12410388SAndreas.Sandberg@ARM.com if (!DTRACE(VIO)) 12510388SAndreas.Sandberg@ARM.com return; 12610388SAndreas.Sandberg@ARM.com 12710388SAndreas.Sandberg@ARM.com const VirtDescriptor *desc(this); 12810388SAndreas.Sandberg@ARM.com do { 12910388SAndreas.Sandberg@ARM.com desc->dump(); 13011321Ssteve.reinhardt@amd.com } while ((desc = desc->next()) != NULL); 13110388SAndreas.Sandberg@ARM.com} 13210388SAndreas.Sandberg@ARM.com 13310388SAndreas.Sandberg@ARM.comVirtDescriptor * 13410388SAndreas.Sandberg@ARM.comVirtDescriptor::next() const 13510388SAndreas.Sandberg@ARM.com{ 13610388SAndreas.Sandberg@ARM.com if (hasNext()) { 13710388SAndreas.Sandberg@ARM.com return queue->getDescriptor(desc.next); 13810388SAndreas.Sandberg@ARM.com } else { 13910388SAndreas.Sandberg@ARM.com return NULL; 14010388SAndreas.Sandberg@ARM.com } 14110388SAndreas.Sandberg@ARM.com} 14210388SAndreas.Sandberg@ARM.com 14310388SAndreas.Sandberg@ARM.comvoid 14410388SAndreas.Sandberg@ARM.comVirtDescriptor::read(size_t offset, uint8_t *dst, size_t size) const 14510388SAndreas.Sandberg@ARM.com{ 14610388SAndreas.Sandberg@ARM.com DPRINTF(VIO, "VirtDescriptor(%p, 0x%x, %i)::read: offset: %i, dst: 0x%x, size: %i\n", 14710388SAndreas.Sandberg@ARM.com this, desc.addr, desc.len, offset, (long)dst, size); 14810388SAndreas.Sandberg@ARM.com assert(size <= desc.len - offset); 14910388SAndreas.Sandberg@ARM.com if (!isIncoming()) 15010388SAndreas.Sandberg@ARM.com panic("Trying to read from outgoing buffer\n"); 15110388SAndreas.Sandberg@ARM.com 15210388SAndreas.Sandberg@ARM.com memProxy->readBlob(desc.addr + offset, dst, size); 15310388SAndreas.Sandberg@ARM.com} 15410388SAndreas.Sandberg@ARM.com 15510388SAndreas.Sandberg@ARM.comvoid 15610388SAndreas.Sandberg@ARM.comVirtDescriptor::write(size_t offset, const uint8_t *src, size_t size) 15710388SAndreas.Sandberg@ARM.com{ 15810388SAndreas.Sandberg@ARM.com DPRINTF(VIO, "VirtDescriptor(%p, 0x%x, %i)::write: offset: %i, src: 0x%x, size: %i\n", 15910388SAndreas.Sandberg@ARM.com this, desc.addr, desc.len, offset, (long)src, size); 16010388SAndreas.Sandberg@ARM.com assert(size <= desc.len - offset); 16110388SAndreas.Sandberg@ARM.com if (!isOutgoing()) 16210388SAndreas.Sandberg@ARM.com panic("Trying to write to incoming buffer\n"); 16310388SAndreas.Sandberg@ARM.com 16414010Sgabeblack@google.com memProxy->writeBlob(desc.addr + offset, src, size); 16510388SAndreas.Sandberg@ARM.com} 16610388SAndreas.Sandberg@ARM.com 16710388SAndreas.Sandberg@ARM.comvoid 16810388SAndreas.Sandberg@ARM.comVirtDescriptor::chainRead(size_t offset, uint8_t *dst, size_t size) const 16910388SAndreas.Sandberg@ARM.com{ 17010388SAndreas.Sandberg@ARM.com const VirtDescriptor *desc(this); 17110388SAndreas.Sandberg@ARM.com const size_t full_size(size); 17210388SAndreas.Sandberg@ARM.com do { 17310388SAndreas.Sandberg@ARM.com if (offset < desc->size()) { 17410388SAndreas.Sandberg@ARM.com const size_t chunk_size(std::min(desc->size() - offset, size)); 17510388SAndreas.Sandberg@ARM.com desc->read(offset, dst, chunk_size); 17610388SAndreas.Sandberg@ARM.com dst += chunk_size; 17710388SAndreas.Sandberg@ARM.com size -= chunk_size; 17810388SAndreas.Sandberg@ARM.com offset = 0; 17910388SAndreas.Sandberg@ARM.com } else { 18010388SAndreas.Sandberg@ARM.com offset -= desc->size(); 18110388SAndreas.Sandberg@ARM.com } 18211321Ssteve.reinhardt@amd.com } while ((desc = desc->next()) != NULL && desc->isIncoming() && size > 0); 18310388SAndreas.Sandberg@ARM.com 18410388SAndreas.Sandberg@ARM.com if (size != 0) { 18510388SAndreas.Sandberg@ARM.com panic("Failed to read %i bytes from chain of %i bytes @ offset %i\n", 18610388SAndreas.Sandberg@ARM.com full_size, chainSize(), offset); 18710388SAndreas.Sandberg@ARM.com } 18810388SAndreas.Sandberg@ARM.com} 18910388SAndreas.Sandberg@ARM.com 19010388SAndreas.Sandberg@ARM.comvoid 19110388SAndreas.Sandberg@ARM.comVirtDescriptor::chainWrite(size_t offset, const uint8_t *src, size_t size) 19210388SAndreas.Sandberg@ARM.com{ 19310388SAndreas.Sandberg@ARM.com VirtDescriptor *desc(this); 19410388SAndreas.Sandberg@ARM.com const size_t full_size(size); 19510388SAndreas.Sandberg@ARM.com do { 19610388SAndreas.Sandberg@ARM.com if (offset < desc->size()) { 19710388SAndreas.Sandberg@ARM.com const size_t chunk_size(std::min(desc->size() - offset, size)); 19810388SAndreas.Sandberg@ARM.com desc->write(offset, src, chunk_size); 19910388SAndreas.Sandberg@ARM.com src += chunk_size; 20010388SAndreas.Sandberg@ARM.com size -= chunk_size; 20110388SAndreas.Sandberg@ARM.com offset = 0; 20210388SAndreas.Sandberg@ARM.com } else { 20310388SAndreas.Sandberg@ARM.com offset -= desc->size(); 20410388SAndreas.Sandberg@ARM.com } 20511321Ssteve.reinhardt@amd.com } while ((desc = desc->next()) != NULL && size > 0); 20610388SAndreas.Sandberg@ARM.com 20710388SAndreas.Sandberg@ARM.com if (size != 0) { 20810388SAndreas.Sandberg@ARM.com panic("Failed to write %i bytes into chain of %i bytes @ offset %i\n", 20910388SAndreas.Sandberg@ARM.com full_size, chainSize(), offset); 21010388SAndreas.Sandberg@ARM.com } 21110388SAndreas.Sandberg@ARM.com} 21210388SAndreas.Sandberg@ARM.com 21310388SAndreas.Sandberg@ARM.comsize_t 21410388SAndreas.Sandberg@ARM.comVirtDescriptor::chainSize() const 21510388SAndreas.Sandberg@ARM.com{ 21610388SAndreas.Sandberg@ARM.com size_t size(0); 21710388SAndreas.Sandberg@ARM.com const VirtDescriptor *desc(this); 21810388SAndreas.Sandberg@ARM.com do { 21910388SAndreas.Sandberg@ARM.com size += desc->size(); 22011321Ssteve.reinhardt@amd.com } while ((desc = desc->next()) != NULL); 22110388SAndreas.Sandberg@ARM.com 22210388SAndreas.Sandberg@ARM.com return size; 22310388SAndreas.Sandberg@ARM.com} 22410388SAndreas.Sandberg@ARM.com 22510388SAndreas.Sandberg@ARM.com 22610388SAndreas.Sandberg@ARM.com 22710388SAndreas.Sandberg@ARM.comVirtQueue::VirtQueue(PortProxy &proxy, uint16_t size) 22810388SAndreas.Sandberg@ARM.com : _size(size), _address(0), memProxy(proxy), 22910388SAndreas.Sandberg@ARM.com avail(proxy, size), used(proxy, size), 23010388SAndreas.Sandberg@ARM.com _last_avail(0) 23110388SAndreas.Sandberg@ARM.com{ 23210388SAndreas.Sandberg@ARM.com descriptors.reserve(_size); 23310388SAndreas.Sandberg@ARM.com for (int i = 0; i < _size; ++i) 23410388SAndreas.Sandberg@ARM.com descriptors.emplace_back(proxy, *this, i); 23510388SAndreas.Sandberg@ARM.com} 23610388SAndreas.Sandberg@ARM.com 23710388SAndreas.Sandberg@ARM.comvoid 23810905Sandreas.sandberg@arm.comVirtQueue::serialize(CheckpointOut &cp) const 23910388SAndreas.Sandberg@ARM.com{ 24010388SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(_address); 24110388SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(_last_avail); 24210388SAndreas.Sandberg@ARM.com} 24310388SAndreas.Sandberg@ARM.com 24410388SAndreas.Sandberg@ARM.comvoid 24510905Sandreas.sandberg@arm.comVirtQueue::unserialize(CheckpointIn &cp) 24610388SAndreas.Sandberg@ARM.com{ 24710388SAndreas.Sandberg@ARM.com Addr addr_in; 24810388SAndreas.Sandberg@ARM.com 24910905Sandreas.sandberg@arm.com paramIn(cp, "_address", addr_in); 25010388SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(_last_avail); 25110388SAndreas.Sandberg@ARM.com 25210388SAndreas.Sandberg@ARM.com // Use the address setter to ensure that the ring buffer addresses 25310388SAndreas.Sandberg@ARM.com // are updated as well. 25410388SAndreas.Sandberg@ARM.com setAddress(addr_in); 25510388SAndreas.Sandberg@ARM.com} 25610388SAndreas.Sandberg@ARM.com 25710388SAndreas.Sandberg@ARM.comvoid 25810388SAndreas.Sandberg@ARM.comVirtQueue::setAddress(Addr address) 25910388SAndreas.Sandberg@ARM.com{ 26010388SAndreas.Sandberg@ARM.com const Addr addr_avail(address + _size * sizeof(struct vring_desc)); 26110388SAndreas.Sandberg@ARM.com const Addr addr_avail_end(addr_avail + sizeof(struct vring_avail) + 26210388SAndreas.Sandberg@ARM.com _size * sizeof(uint16_t)); 26310388SAndreas.Sandberg@ARM.com const Addr addr_used((addr_avail_end + sizeof(uint16_t) + 26410388SAndreas.Sandberg@ARM.com (ALIGN_SIZE - 1)) & ~(ALIGN_SIZE - 1)); 26510388SAndreas.Sandberg@ARM.com _address = address; 26610388SAndreas.Sandberg@ARM.com avail.setAddress(addr_avail); 26710388SAndreas.Sandberg@ARM.com used.setAddress(addr_used); 26810388SAndreas.Sandberg@ARM.com} 26910388SAndreas.Sandberg@ARM.com 27010388SAndreas.Sandberg@ARM.comVirtDescriptor * 27110388SAndreas.Sandberg@ARM.comVirtQueue::consumeDescriptor() 27210388SAndreas.Sandberg@ARM.com{ 27310388SAndreas.Sandberg@ARM.com avail.read(); 27410388SAndreas.Sandberg@ARM.com DPRINTF(VIO, "consumeDescriptor: _last_avail: %i, avail.idx: %i (->%i)\n", 27510388SAndreas.Sandberg@ARM.com _last_avail, avail.header.index, 27610388SAndreas.Sandberg@ARM.com avail.ring[_last_avail % used.ring.size()]); 27710388SAndreas.Sandberg@ARM.com if (_last_avail == avail.header.index) 27810388SAndreas.Sandberg@ARM.com return NULL; 27910388SAndreas.Sandberg@ARM.com 28010388SAndreas.Sandberg@ARM.com VirtDescriptor::Index index(avail.ring[_last_avail % used.ring.size()]); 28110388SAndreas.Sandberg@ARM.com ++_last_avail; 28210388SAndreas.Sandberg@ARM.com 28310388SAndreas.Sandberg@ARM.com VirtDescriptor *d(&descriptors[index]); 28410388SAndreas.Sandberg@ARM.com d->updateChain(); 28510388SAndreas.Sandberg@ARM.com 28610388SAndreas.Sandberg@ARM.com return d; 28710388SAndreas.Sandberg@ARM.com} 28810388SAndreas.Sandberg@ARM.com 28910388SAndreas.Sandberg@ARM.comvoid 29010388SAndreas.Sandberg@ARM.comVirtQueue::produceDescriptor(VirtDescriptor *desc, uint32_t len) 29110388SAndreas.Sandberg@ARM.com{ 29210388SAndreas.Sandberg@ARM.com used.readHeader(); 29310388SAndreas.Sandberg@ARM.com DPRINTF(VIO, "produceDescriptor: dscIdx: %i, len: %i, used.idx: %i\n", 29410388SAndreas.Sandberg@ARM.com desc->index(), len, used.header.index); 29510388SAndreas.Sandberg@ARM.com 29610388SAndreas.Sandberg@ARM.com struct vring_used_elem &e(used.ring[used.header.index % used.ring.size()]); 29710388SAndreas.Sandberg@ARM.com e.id = desc->index(); 29810388SAndreas.Sandberg@ARM.com e.len = len; 29910388SAndreas.Sandberg@ARM.com used.header.index += 1; 30010388SAndreas.Sandberg@ARM.com used.write(); 30110388SAndreas.Sandberg@ARM.com} 30210388SAndreas.Sandberg@ARM.com 30310388SAndreas.Sandberg@ARM.comvoid 30410388SAndreas.Sandberg@ARM.comVirtQueue::dump() const 30510388SAndreas.Sandberg@ARM.com{ 30610388SAndreas.Sandberg@ARM.com if (!DTRACE(VIO)) 30710388SAndreas.Sandberg@ARM.com return; 30810388SAndreas.Sandberg@ARM.com 30910388SAndreas.Sandberg@ARM.com for (const VirtDescriptor &d : descriptors) 31010388SAndreas.Sandberg@ARM.com d.dump(); 31110388SAndreas.Sandberg@ARM.com} 31210388SAndreas.Sandberg@ARM.com 31310388SAndreas.Sandberg@ARM.comvoid 31410388SAndreas.Sandberg@ARM.comVirtQueue::onNotify() 31510388SAndreas.Sandberg@ARM.com{ 31610388SAndreas.Sandberg@ARM.com DPRINTF(VIO, "onNotify\n"); 31710388SAndreas.Sandberg@ARM.com 31810388SAndreas.Sandberg@ARM.com // Consume all pending descriptors from the input queue. 31910388SAndreas.Sandberg@ARM.com VirtDescriptor *d; 32011321Ssteve.reinhardt@amd.com while ((d = consumeDescriptor()) != NULL) 32110388SAndreas.Sandberg@ARM.com onNotifyDescriptor(d); 32210388SAndreas.Sandberg@ARM.com} 32310388SAndreas.Sandberg@ARM.com 32410388SAndreas.Sandberg@ARM.com 32510388SAndreas.Sandberg@ARM.comVirtIODeviceBase::VirtIODeviceBase(Params *params, DeviceId id, 32610388SAndreas.Sandberg@ARM.com size_t config_size, FeatureBits features) 32710388SAndreas.Sandberg@ARM.com : SimObject(params), 32810388SAndreas.Sandberg@ARM.com guestFeatures(0), 32910388SAndreas.Sandberg@ARM.com deviceId(id), configSize(config_size), deviceFeatures(features), 33010388SAndreas.Sandberg@ARM.com _deviceStatus(0), _queueSelect(0), 33110388SAndreas.Sandberg@ARM.com transKick(NULL) 33210388SAndreas.Sandberg@ARM.com{ 33310388SAndreas.Sandberg@ARM.com} 33410388SAndreas.Sandberg@ARM.com 33510388SAndreas.Sandberg@ARM.com 33610388SAndreas.Sandberg@ARM.comVirtIODeviceBase::~VirtIODeviceBase() 33710388SAndreas.Sandberg@ARM.com{ 33810388SAndreas.Sandberg@ARM.com} 33910388SAndreas.Sandberg@ARM.com 34010388SAndreas.Sandberg@ARM.comvoid 34110905Sandreas.sandberg@arm.comVirtIODeviceBase::serialize(CheckpointOut &cp) const 34210388SAndreas.Sandberg@ARM.com{ 34310388SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(guestFeatures); 34410905Sandreas.sandberg@arm.com SERIALIZE_SCALAR(_deviceStatus); 34510388SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(_queueSelect); 34610905Sandreas.sandberg@arm.com for (QueueID i = 0; i < _queues.size(); ++i) 34710905Sandreas.sandberg@arm.com _queues[i]->serializeSection(cp, csprintf("_queues.%i", i)); 34810388SAndreas.Sandberg@ARM.com} 34910388SAndreas.Sandberg@ARM.com 35010388SAndreas.Sandberg@ARM.comvoid 35110905Sandreas.sandberg@arm.comVirtIODeviceBase::unserialize(CheckpointIn &cp) 35210388SAndreas.Sandberg@ARM.com{ 35310388SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(guestFeatures); 35410905Sandreas.sandberg@arm.com UNSERIALIZE_SCALAR(_deviceStatus); 35510388SAndreas.Sandberg@ARM.com UNSERIALIZE_SCALAR(_queueSelect); 35610388SAndreas.Sandberg@ARM.com for (QueueID i = 0; i < _queues.size(); ++i) 35710905Sandreas.sandberg@arm.com _queues[i]->unserializeSection(cp, csprintf("_queues.%i", i)); 35810388SAndreas.Sandberg@ARM.com} 35910388SAndreas.Sandberg@ARM.com 36010388SAndreas.Sandberg@ARM.comvoid 36110388SAndreas.Sandberg@ARM.comVirtIODeviceBase::reset() 36210388SAndreas.Sandberg@ARM.com{ 36310388SAndreas.Sandberg@ARM.com _queueSelect = 0; 36410388SAndreas.Sandberg@ARM.com guestFeatures = 0; 36510388SAndreas.Sandberg@ARM.com _deviceStatus = 0; 36610388SAndreas.Sandberg@ARM.com 36710388SAndreas.Sandberg@ARM.com for (QueueID i = 0; i < _queues.size(); ++i) 36810388SAndreas.Sandberg@ARM.com _queues[i]->setAddress(0); 36910388SAndreas.Sandberg@ARM.com} 37010388SAndreas.Sandberg@ARM.com 37110388SAndreas.Sandberg@ARM.comvoid 37210388SAndreas.Sandberg@ARM.comVirtIODeviceBase::onNotify(QueueID idx) 37310388SAndreas.Sandberg@ARM.com{ 37410388SAndreas.Sandberg@ARM.com DPRINTF(VIO, "onNotify: idx: %i\n", idx); 37510388SAndreas.Sandberg@ARM.com if (idx >= _queues.size()) { 37610388SAndreas.Sandberg@ARM.com panic("Guest tried to notify queue (%i), but only %i " 37710388SAndreas.Sandberg@ARM.com "queues registered.\n", 37810388SAndreas.Sandberg@ARM.com idx, _queues.size()); 37910388SAndreas.Sandberg@ARM.com } 38010388SAndreas.Sandberg@ARM.com _queues[idx]->onNotify(); 38110388SAndreas.Sandberg@ARM.com} 38210388SAndreas.Sandberg@ARM.com 38310388SAndreas.Sandberg@ARM.comvoid 38410388SAndreas.Sandberg@ARM.comVirtIODeviceBase::setGuestFeatures(FeatureBits features) 38510388SAndreas.Sandberg@ARM.com{ 38610388SAndreas.Sandberg@ARM.com DPRINTF(VIO, "Setting guest features: 0x%x\n", features); 38710388SAndreas.Sandberg@ARM.com if (~deviceFeatures & features) { 38810388SAndreas.Sandberg@ARM.com panic("Guest tried to enable unsupported features:\n" 38910388SAndreas.Sandberg@ARM.com "Device features: 0x%x\n" 39010388SAndreas.Sandberg@ARM.com "Requested features: 0x%x\n", 39110388SAndreas.Sandberg@ARM.com deviceFeatures, features); 39210388SAndreas.Sandberg@ARM.com } 39310388SAndreas.Sandberg@ARM.com guestFeatures = features; 39410388SAndreas.Sandberg@ARM.com} 39510388SAndreas.Sandberg@ARM.com 39610388SAndreas.Sandberg@ARM.com 39710388SAndreas.Sandberg@ARM.comvoid 39810388SAndreas.Sandberg@ARM.comVirtIODeviceBase::setDeviceStatus(DeviceStatus status) 39910388SAndreas.Sandberg@ARM.com{ 40010388SAndreas.Sandberg@ARM.com _deviceStatus = status; 40110388SAndreas.Sandberg@ARM.com DPRINTF(VIO, "ACK: %i, DRIVER: %i, DRIVER_OK: %i, FAILED: %i\n", 40210388SAndreas.Sandberg@ARM.com status.acknowledge, status.driver, status.driver_ok, status.failed); 40310388SAndreas.Sandberg@ARM.com if (status == 0) 40410388SAndreas.Sandberg@ARM.com reset(); 40510388SAndreas.Sandberg@ARM.com} 40610388SAndreas.Sandberg@ARM.com 40710388SAndreas.Sandberg@ARM.comvoid 40810388SAndreas.Sandberg@ARM.comVirtIODeviceBase::readConfig(PacketPtr pkt, Addr cfgOffset) 40910388SAndreas.Sandberg@ARM.com{ 41010388SAndreas.Sandberg@ARM.com panic("Unhandled device config read (offset: 0x%x).\n", cfgOffset); 41110388SAndreas.Sandberg@ARM.com} 41210388SAndreas.Sandberg@ARM.com 41310388SAndreas.Sandberg@ARM.comvoid 41410388SAndreas.Sandberg@ARM.comVirtIODeviceBase::writeConfig(PacketPtr pkt, Addr cfgOffset) 41510388SAndreas.Sandberg@ARM.com{ 41610388SAndreas.Sandberg@ARM.com panic("Unhandled device config write (offset: 0x%x).\n", cfgOffset); 41710388SAndreas.Sandberg@ARM.com} 41810388SAndreas.Sandberg@ARM.com 41910388SAndreas.Sandberg@ARM.comvoid 42010388SAndreas.Sandberg@ARM.comVirtIODeviceBase::readConfigBlob(PacketPtr pkt, Addr cfgOffset, const uint8_t *cfg) 42110388SAndreas.Sandberg@ARM.com{ 42210388SAndreas.Sandberg@ARM.com const unsigned size(pkt->getSize()); 42310388SAndreas.Sandberg@ARM.com 42410388SAndreas.Sandberg@ARM.com if (cfgOffset + size > configSize) 42510388SAndreas.Sandberg@ARM.com panic("Config read out of bounds.\n"); 42610388SAndreas.Sandberg@ARM.com 42710602SAndreas.Sandberg@ARM.com pkt->makeResponse(); 42810388SAndreas.Sandberg@ARM.com pkt->setData(const_cast<uint8_t *>(cfg) + cfgOffset); 42910388SAndreas.Sandberg@ARM.com} 43010388SAndreas.Sandberg@ARM.com 43110388SAndreas.Sandberg@ARM.comvoid 43210388SAndreas.Sandberg@ARM.comVirtIODeviceBase::writeConfigBlob(PacketPtr pkt, Addr cfgOffset, uint8_t *cfg) 43310388SAndreas.Sandberg@ARM.com{ 43410388SAndreas.Sandberg@ARM.com const unsigned size(pkt->getSize()); 43510388SAndreas.Sandberg@ARM.com 43610388SAndreas.Sandberg@ARM.com if (cfgOffset + size > configSize) 43710388SAndreas.Sandberg@ARM.com panic("Config write out of bounds.\n"); 43810388SAndreas.Sandberg@ARM.com 43910602SAndreas.Sandberg@ARM.com pkt->makeResponse(); 44010388SAndreas.Sandberg@ARM.com pkt->writeData((uint8_t *)cfg + cfgOffset); 44110388SAndreas.Sandberg@ARM.com} 44210388SAndreas.Sandberg@ARM.com 44310388SAndreas.Sandberg@ARM.com 44410388SAndreas.Sandberg@ARM.comconst VirtQueue & 44510388SAndreas.Sandberg@ARM.comVirtIODeviceBase::getCurrentQueue() const 44610388SAndreas.Sandberg@ARM.com{ 44710388SAndreas.Sandberg@ARM.com if (_queueSelect >= _queues.size()) 44810388SAndreas.Sandberg@ARM.com panic("Guest tried to access non-existing VirtQueue (%i).\n", _queueSelect); 44910388SAndreas.Sandberg@ARM.com 45010388SAndreas.Sandberg@ARM.com return *_queues[_queueSelect]; 45110388SAndreas.Sandberg@ARM.com} 45210388SAndreas.Sandberg@ARM.com 45310388SAndreas.Sandberg@ARM.comVirtQueue & 45410388SAndreas.Sandberg@ARM.comVirtIODeviceBase::getCurrentQueue() 45510388SAndreas.Sandberg@ARM.com{ 45610388SAndreas.Sandberg@ARM.com if (_queueSelect >= _queues.size()) 45710388SAndreas.Sandberg@ARM.com panic("Guest tried to access non-existing VirtQueue (%i).\n", _queueSelect); 45810388SAndreas.Sandberg@ARM.com 45910388SAndreas.Sandberg@ARM.com return *_queues[_queueSelect]; 46010388SAndreas.Sandberg@ARM.com} 46110388SAndreas.Sandberg@ARM.com 46210388SAndreas.Sandberg@ARM.comvoid 46310388SAndreas.Sandberg@ARM.comVirtIODeviceBase::setQueueAddress(uint32_t address) 46410388SAndreas.Sandberg@ARM.com{ 46510388SAndreas.Sandberg@ARM.com getCurrentQueue().setAddress(address * VirtQueue::ALIGN_SIZE); 46610388SAndreas.Sandberg@ARM.com} 46710388SAndreas.Sandberg@ARM.com 46810388SAndreas.Sandberg@ARM.comuint32_t 46910388SAndreas.Sandberg@ARM.comVirtIODeviceBase::getQueueAddress() const 47010388SAndreas.Sandberg@ARM.com{ 47110388SAndreas.Sandberg@ARM.com Addr address(getCurrentQueue().getAddress()); 47210388SAndreas.Sandberg@ARM.com assert(!(address & ((1 >> VirtQueue::ALIGN_BITS) - 1))); 47310388SAndreas.Sandberg@ARM.com return address >> VirtQueue::ALIGN_BITS; 47410388SAndreas.Sandberg@ARM.com} 47510388SAndreas.Sandberg@ARM.com 47610388SAndreas.Sandberg@ARM.comvoid 47710388SAndreas.Sandberg@ARM.comVirtIODeviceBase::registerQueue(VirtQueue &queue) 47810388SAndreas.Sandberg@ARM.com{ 47910388SAndreas.Sandberg@ARM.com _queues.push_back(&queue); 48010388SAndreas.Sandberg@ARM.com} 48111931Sandreas.sandberg@arm.com 48211931Sandreas.sandberg@arm.com 48311931Sandreas.sandberg@arm.comVirtIODummyDevice::VirtIODummyDevice(VirtIODummyDeviceParams *params) 48411931Sandreas.sandberg@arm.com : VirtIODeviceBase(params, ID_INVALID, 0, 0) 48511931Sandreas.sandberg@arm.com{ 48611931Sandreas.sandberg@arm.com} 48711931Sandreas.sandberg@arm.com 48811931Sandreas.sandberg@arm.comVirtIODummyDevice * 48911931Sandreas.sandberg@arm.comVirtIODummyDeviceParams::create() 49011931Sandreas.sandberg@arm.com{ 49111931Sandreas.sandberg@arm.com return new VirtIODummyDevice(this); 49211931Sandreas.sandberg@arm.com} 493