base.cc revision 10905
19243SN/A/* 210206Sandreas.hansson@arm.com * Copyright (c) 2014 ARM Limited 39243SN/A * All rights reserved 49243SN/A * 59243SN/A * The license below extends only to copyright in the software and shall 69243SN/A * not be construed as granting a license to any other intellectual 79243SN/A * property including but not limited to intellectual property relating 89243SN/A * to a hardware implementation of the functionality of the software 99243SN/A * licensed hereunder. You may use the software subject to the license 109243SN/A * terms below provided that you ensure that this notice is replicated 119243SN/A * unmodified and in its entirety in all distributions of the software, 129243SN/A * modified or unmodified, in source code or in binary form. 139243SN/A * 149831SN/A * Redistribution and use in source and binary forms, with or without 159831SN/A * modification, are permitted provided that the following conditions are 169831SN/A * met: redistributions of source code must retain the above copyright 179243SN/A * notice, this list of conditions and the following disclaimer; 189243SN/A * redistributions in binary form must reproduce the above copyright 199243SN/A * notice, this list of conditions and the following disclaimer in the 209243SN/A * documentation and/or other materials provided with the distribution; 219243SN/A * neither the name of the copyright holders nor the names of its 229243SN/A * contributors may be used to endorse or promote products derived from 239243SN/A * this software without specific prior written permission. 249243SN/A * 259243SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 269243SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 279243SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 289243SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 299243SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 309243SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 319243SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 329243SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 339243SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 349243SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 359243SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 369243SN/A * 379243SN/A * Authors: Andreas Sandberg 389243SN/A */ 399243SN/A 409243SN/A#include "debug/VIO.hh" 419243SN/A#include "dev/virtio/base.hh" 429967SN/A#include "params/VirtIODeviceBase.hh" 439243SN/A 449243SN/AVirtDescriptor::VirtDescriptor(PortProxy &_memProxy, VirtQueue &_queue, 4510146Sandreas.hansson@arm.com Index descIndex) 469356SN/A : memProxy(&_memProxy), queue(&_queue), _index(descIndex), 4710146Sandreas.hansson@arm.com desc{0, 0, 0, 0} 4810208Sandreas.hansson@arm.com{ 499352SN/A} 5010146Sandreas.hansson@arm.com 519814SN/AVirtDescriptor::VirtDescriptor(VirtDescriptor &&other) noexcept 529243SN/A{ 539243SN/A *this = std::forward<VirtDescriptor>(other); 549243SN/A} 5510146Sandreas.hansson@arm.com 569243SN/AVirtDescriptor::~VirtDescriptor() noexcept 579243SN/A{ 589243SN/A} 5910211Sandreas.hansson@arm.com 6010208Sandreas.hansson@arm.comVirtDescriptor & 6110208Sandreas.hansson@arm.comVirtDescriptor::operator=(VirtDescriptor &&rhs) noexcept 6210208Sandreas.hansson@arm.com{ 639831SN/A memProxy = std::move(rhs.memProxy); 649831SN/A queue = std::move(rhs.queue); 659831SN/A _index = std::move(rhs._index); 669831SN/A desc = std::move(rhs.desc); 679831SN/A 6810140SN/A return *this; 699243SN/A} 709566SN/A 719243SN/Avoid 729243SN/AVirtDescriptor::update() 7310140SN/A{ 7410140SN/A const Addr vq_addr(queue->getAddress()); 7510147Sandreas.hansson@arm.com // Check if the queue has been initialized yet 7610147Sandreas.hansson@arm.com if (vq_addr == 0) 7710206Sandreas.hansson@arm.com return; 7810210Sandreas.hansson@arm.com 7910212Sandreas.hansson@arm.com assert(_index < queue->getSize()); 809488SN/A const Addr desc_addr(vq_addr + sizeof(desc) * _index); 819243SN/A vring_desc guest_desc; 829243SN/A memProxy->readBlob(desc_addr, (uint8_t *)&guest_desc, sizeof(guest_desc)); 8310141SN/A desc = vtoh_legacy(guest_desc); 849726SN/A DPRINTF(VIO, 859726SN/A "VirtDescriptor(%i): Addr: 0x%x, Len: %i, Flags: 0x%x, " 8610208Sandreas.hansson@arm.com "Next: 0x%x\n", 8710208Sandreas.hansson@arm.com _index, desc.addr, desc.len, desc.flags, desc.next); 8810208Sandreas.hansson@arm.com} 899243SN/A 909243SN/Avoid 919243SN/AVirtDescriptor::updateChain() 929243SN/A{ 939969SN/A VirtDescriptor *desc(this); 949243SN/A do { 959243SN/A desc->update(); 969969SN/A } while((desc = desc->next()) != NULL && desc != this); 979243SN/A 989243SN/A if (desc == this) 9910140SN/A panic("Loop in descriptor chain!\n"); 10010140SN/A} 10110140SN/A 10210140SN/Avoid 10310140SN/AVirtDescriptor::dump() const 1049243SN/A{ 1059243SN/A if (!DTRACE(VIO)) 1069567SN/A return; 1079243SN/A 1089243SN/A DPRINTF(VIO, "Descriptor[%i]: " 1099243SN/A "Addr: 0x%x, Len: %i, Flags: 0x%x, Next: 0x%x\n", 1109831SN/A _index, desc.addr, desc.len, desc.flags, desc.next); 1119831SN/A 1129831SN/A if (isIncoming()) { 1139831SN/A uint8_t data[desc.len]; 1149831SN/A read(0, data, desc.len); 1159243SN/A DDUMP(VIO, data, desc.len); 1169566SN/A } 1179566SN/A} 11810143SN/A 1199566SN/Avoid 1209566SN/AVirtDescriptor::dumpChain() const 12110136SN/A{ 1229831SN/A if (!DTRACE(VIO)) 12310143SN/A return; 12410136SN/A 1259566SN/A const VirtDescriptor *desc(this); 12610136SN/A do { 12710136SN/A desc->dump(); 12810143SN/A } while((desc = desc->next()) != NULL); 12910136SN/A} 1309669SN/A 13110136SN/AVirtDescriptor * 13210136SN/AVirtDescriptor::next() const 13310143SN/A{ 13410136SN/A if (hasNext()) { 1359566SN/A return queue->getDescriptor(desc.next); 1369566SN/A } else { 13710207Sandreas.hansson@arm.com return NULL; 13810207Sandreas.hansson@arm.com } 13910207Sandreas.hansson@arm.com} 14010207Sandreas.hansson@arm.com 14110207Sandreas.hansson@arm.comvoid 14210207Sandreas.hansson@arm.comVirtDescriptor::read(size_t offset, uint8_t *dst, size_t size) const 1439243SN/A{ 1449243SN/A DPRINTF(VIO, "VirtDescriptor(%p, 0x%x, %i)::read: offset: %i, dst: 0x%x, size: %i\n", 1459243SN/A this, desc.addr, desc.len, offset, (long)dst, size); 14610146Sandreas.hansson@arm.com assert(size <= desc.len - offset); 14710140SN/A if (!isIncoming()) 14810140SN/A panic("Trying to read from outgoing buffer\n"); 14910146Sandreas.hansson@arm.com 15010140SN/A memProxy->readBlob(desc.addr + offset, dst, size); 15110140SN/A} 15210140SN/A 15310140SN/Avoid 15410140SN/AVirtDescriptor::write(size_t offset, const uint8_t *src, size_t size) 15510140SN/A{ 15610146Sandreas.hansson@arm.com DPRINTF(VIO, "VirtDescriptor(%p, 0x%x, %i)::write: offset: %i, src: 0x%x, size: %i\n", 1579243SN/A this, desc.addr, desc.len, offset, (long)src, size); 15810143SN/A assert(size <= desc.len - offset); 15910143SN/A if (!isOutgoing()) 16010208Sandreas.hansson@arm.com panic("Trying to write to incoming buffer\n"); 16110143SN/A 16210206Sandreas.hansson@arm.com memProxy->writeBlob(desc.addr + offset, const_cast<uint8_t *>(src), size); 16310206Sandreas.hansson@arm.com} 16410206Sandreas.hansson@arm.com 16510206Sandreas.hansson@arm.comvoid 16610206Sandreas.hansson@arm.comVirtDescriptor::chainRead(size_t offset, uint8_t *dst, size_t size) const 16710206Sandreas.hansson@arm.com{ 16810207Sandreas.hansson@arm.com const VirtDescriptor *desc(this); 16910207Sandreas.hansson@arm.com const size_t full_size(size); 17010207Sandreas.hansson@arm.com do { 1719243SN/A if (offset < desc->size()) { 1729243SN/A const size_t chunk_size(std::min(desc->size() - offset, size)); 1739243SN/A desc->read(offset, dst, chunk_size); 17410146Sandreas.hansson@arm.com dst += chunk_size; 1759243SN/A size -= chunk_size; 1769243SN/A offset = 0; 1779243SN/A } else { 1789243SN/A offset -= desc->size(); 1799243SN/A } 1809243SN/A } while((desc = desc->next()) != NULL && desc->isIncoming() && size > 0); 1819243SN/A 1829243SN/A if (size != 0) { 1839243SN/A panic("Failed to read %i bytes from chain of %i bytes @ offset %i\n", 1849243SN/A full_size, chainSize(), offset); 1859243SN/A } 1869243SN/A} 1879243SN/A 1889243SN/Avoid 1899243SN/AVirtDescriptor::chainWrite(size_t offset, const uint8_t *src, size_t size) 1909243SN/A{ 19110146Sandreas.hansson@arm.com VirtDescriptor *desc(this); 1929243SN/A const size_t full_size(size); 1939831SN/A do { 1949831SN/A if (offset < desc->size()) { 1959831SN/A const size_t chunk_size(std::min(desc->size() - offset, size)); 1969243SN/A desc->write(offset, src, chunk_size); 1979831SN/A src += chunk_size; 1989831SN/A size -= chunk_size; 1999243SN/A offset = 0; 2009243SN/A } else { 2019243SN/A offset -= desc->size(); 20210146Sandreas.hansson@arm.com } 2039243SN/A } while((desc = desc->next()) != NULL && size > 0); 2049831SN/A 2059831SN/A if (size != 0) { 2069831SN/A panic("Failed to write %i bytes into chain of %i bytes @ offset %i\n", 2079243SN/A full_size, chainSize(), offset); 2089243SN/A } 20910146Sandreas.hansson@arm.com} 21010146Sandreas.hansson@arm.com 21110143SN/Asize_t 2129243SN/AVirtDescriptor::chainSize() const 2139669SN/A{ 21410136SN/A size_t size(0); 21510136SN/A const VirtDescriptor *desc(this); 2169243SN/A do { 2179967SN/A size += desc->size(); 2189243SN/A } while((desc = desc->next()) != NULL); 2199243SN/A 2209243SN/A return size; 2219831SN/A} 2229243SN/A 2239491SN/A 2249831SN/A 22510136SN/AVirtQueue::VirtQueue(PortProxy &proxy, uint16_t size) 2269491SN/A : _size(size), _address(0), memProxy(proxy), 2279491SN/A avail(proxy, size), used(proxy, size), 2289831SN/A _last_avail(0) 2299243SN/A{ 2309669SN/A descriptors.reserve(_size); 2319566SN/A for (int i = 0; i < _size; ++i) 2329566SN/A descriptors.emplace_back(proxy, *this, i); 2339669SN/A} 2349669SN/A 2359669SN/Avoid 2369669SN/AVirtQueue::serialize(CheckpointOut &cp) const 2379669SN/A{ 2389669SN/A SERIALIZE_SCALAR(_address); 2399669SN/A SERIALIZE_SCALAR(_last_avail); 2409669SN/A} 2419669SN/A 2429669SN/Avoid 2439669SN/AVirtQueue::unserialize(CheckpointIn &cp) 2449669SN/A{ 2459669SN/A Addr addr_in; 24610136SN/A 2479669SN/A paramIn(cp, "_address", addr_in); 2489669SN/A UNSERIALIZE_SCALAR(_last_avail); 2499669SN/A 2509669SN/A // Use the address setter to ensure that the ring buffer addresses 2519831SN/A // are updated as well. 2529669SN/A setAddress(addr_in); 2539669SN/A} 2549491SN/A 2559243SN/Avoid 2569243SN/AVirtQueue::setAddress(Addr address) 2579243SN/A{ 2589491SN/A const Addr addr_avail(address + _size * sizeof(struct vring_desc)); 2599491SN/A const Addr addr_avail_end(addr_avail + sizeof(struct vring_avail) + 2609243SN/A _size * sizeof(uint16_t)); 2619243SN/A const Addr addr_used((addr_avail_end + sizeof(uint16_t) + 2629243SN/A (ALIGN_SIZE - 1)) & ~(ALIGN_SIZE - 1)); 2639491SN/A _address = address; 2649243SN/A avail.setAddress(addr_avail); 2659243SN/A used.setAddress(addr_used); 26610136SN/A} 2679491SN/A 2689491SN/AVirtDescriptor * 2699491SN/AVirtQueue::consumeDescriptor() 2709566SN/A{ 2719566SN/A avail.read(); 2729566SN/A DPRINTF(VIO, "consumeDescriptor: _last_avail: %i, avail.idx: %i (->%i)\n", 2739566SN/A _last_avail, avail.header.index, 2749566SN/A avail.ring[_last_avail % used.ring.size()]); 2759491SN/A if (_last_avail == avail.header.index) 2769491SN/A return NULL; 2779243SN/A 2789243SN/A VirtDescriptor::Index index(avail.ring[_last_avail % used.ring.size()]); 2799243SN/A ++_last_avail; 2809491SN/A 2819243SN/A VirtDescriptor *d(&descriptors[index]); 2829243SN/A d->updateChain(); 2839243SN/A 2849491SN/A return d; 2859491SN/A} 2869831SN/A 2879243SN/Avoid 2889491SN/AVirtQueue::produceDescriptor(VirtDescriptor *desc, uint32_t len) 2899243SN/A{ 2909243SN/A used.readHeader(); 2919243SN/A DPRINTF(VIO, "produceDescriptor: dscIdx: %i, len: %i, used.idx: %i\n", 2929243SN/A desc->index(), len, used.header.index); 2939243SN/A 2949243SN/A struct vring_used_elem &e(used.ring[used.header.index % used.ring.size()]); 2959243SN/A e.id = desc->index(); 2969243SN/A e.len = len; 2979243SN/A used.header.index += 1; 2989243SN/A used.write(); 2999831SN/A} 3009243SN/A 3019243SN/Avoid 3029567SN/AVirtQueue::dump() const 3039567SN/A{ 3049967SN/A if (!DTRACE(VIO)) 3059967SN/A return; 3069967SN/A 3079243SN/A for (const VirtDescriptor &d : descriptors) 3089243SN/A d.dump(); 3099243SN/A} 31010146Sandreas.hansson@arm.com 3119243SN/Avoid 3129243SN/AVirtQueue::onNotify() 3139243SN/A{ 3149243SN/A DPRINTF(VIO, "onNotify\n"); 3159243SN/A 3169831SN/A // Consume all pending descriptors from the input queue. 3179831SN/A VirtDescriptor *d; 3189831SN/A while((d = consumeDescriptor()) != NULL) 3199831SN/A onNotifyDescriptor(d); 3209831SN/A} 3219831SN/A 3229831SN/A 3239831SN/AVirtIODeviceBase::VirtIODeviceBase(Params *params, DeviceId id, 3249243SN/A size_t config_size, FeatureBits features) 3259831SN/A : SimObject(params), 3269831SN/A guestFeatures(0), 3279831SN/A deviceId(id), configSize(config_size), deviceFeatures(features), 3289831SN/A _deviceStatus(0), _queueSelect(0), 3299831SN/A transKick(NULL) 3309831SN/A{ 3319831SN/A} 3329243SN/A 3339831SN/A 3349831SN/AVirtIODeviceBase::~VirtIODeviceBase() 3359831SN/A{ 3369833SN/A} 3379832SN/A 3389832SN/Avoid 3399832SN/AVirtIODeviceBase::serialize(CheckpointOut &cp) const 3409832SN/A{ 3419831SN/A SERIALIZE_SCALAR(guestFeatures); 3429831SN/A SERIALIZE_SCALAR(_deviceStatus); 3439831SN/A SERIALIZE_SCALAR(_queueSelect); 3449831SN/A for (QueueID i = 0; i < _queues.size(); ++i) 3459831SN/A _queues[i]->serializeSection(cp, csprintf("_queues.%i", i)); 3469975SN/A} 3479831SN/A 3489831SN/Avoid 3499243SN/AVirtIODeviceBase::unserialize(CheckpointIn &cp) 3509831SN/A{ 3519831SN/A UNSERIALIZE_SCALAR(guestFeatures); 3529831SN/A UNSERIALIZE_SCALAR(_deviceStatus); 3539831SN/A UNSERIALIZE_SCALAR(_queueSelect); 3549831SN/A for (QueueID i = 0; i < _queues.size(); ++i) 3559831SN/A _queues[i]->unserializeSection(cp, csprintf("_queues.%i", i)); 3569831SN/A} 3579831SN/A 3589831SN/Avoid 3599831SN/AVirtIODeviceBase::reset() 3609831SN/A{ 3619831SN/A _queueSelect = 0; 3629966SN/A guestFeatures = 0; 3639831SN/A _deviceStatus = 0; 3649831SN/A 3659831SN/A for (QueueID i = 0; i < _queues.size(); ++i) 3669831SN/A _queues[i]->setAddress(0); 3679831SN/A} 3689831SN/A 3699831SN/Avoid 3709831SN/AVirtIODeviceBase::onNotify(QueueID idx) 3719831SN/A{ 3729831SN/A DPRINTF(VIO, "onNotify: idx: %i\n", idx); 3739831SN/A if (idx >= _queues.size()) { 3749831SN/A panic("Guest tried to notify queue (%i), but only %i " 3759831SN/A "queues registered.\n", 3769831SN/A idx, _queues.size()); 3779831SN/A } 3789243SN/A _queues[idx]->onNotify(); 3799243SN/A} 3809831SN/A 3819831SN/Avoid 3829831SN/AVirtIODeviceBase::setGuestFeatures(FeatureBits features) 3839831SN/A{ 3849831SN/A DPRINTF(VIO, "Setting guest features: 0x%x\n", features); 3859243SN/A if (~deviceFeatures & features) { 3869831SN/A panic("Guest tried to enable unsupported features:\n" 3879831SN/A "Device features: 0x%x\n" 3889831SN/A "Requested features: 0x%x\n", 3899243SN/A deviceFeatures, features); 39010206Sandreas.hansson@arm.com } 39110206Sandreas.hansson@arm.com guestFeatures = features; 39210206Sandreas.hansson@arm.com} 3939567SN/A 3949567SN/A 3959243SN/Avoid 3969243SN/AVirtIODeviceBase::setDeviceStatus(DeviceStatus status) 3979243SN/A{ 3989243SN/A _deviceStatus = status; 39910146Sandreas.hansson@arm.com DPRINTF(VIO, "ACK: %i, DRIVER: %i, DRIVER_OK: %i, FAILED: %i\n", 4009243SN/A status.acknowledge, status.driver, status.driver_ok, status.failed); 4019243SN/A if (status == 0) 4029243SN/A reset(); 4039243SN/A} 4049243SN/A 4059831SN/Avoid 4069831SN/AVirtIODeviceBase::readConfig(PacketPtr pkt, Addr cfgOffset) 4079831SN/A{ 4089831SN/A panic("Unhandled device config read (offset: 0x%x).\n", cfgOffset); 4099831SN/A} 4109831SN/A 4119831SN/Avoid 4129831SN/AVirtIODeviceBase::writeConfig(PacketPtr pkt, Addr cfgOffset) 4139243SN/A{ 4149832SN/A panic("Unhandled device config write (offset: 0x%x).\n", cfgOffset); 4159838SN/A} 4169838SN/A 4179838SN/Avoid 4189832SN/AVirtIODeviceBase::readConfigBlob(PacketPtr pkt, Addr cfgOffset, const uint8_t *cfg) 4199832SN/A{ 4209243SN/A const unsigned size(pkt->getSize()); 4219832SN/A 4229832SN/A if (cfgOffset + size > configSize) 4239832SN/A panic("Config read out of bounds.\n"); 4249832SN/A 4259838SN/A pkt->makeResponse(); 4269838SN/A pkt->setData(const_cast<uint8_t *>(cfg) + cfgOffset); 4279838SN/A} 4289832SN/A 4299832SN/Avoid 4309832SN/AVirtIODeviceBase::writeConfigBlob(PacketPtr pkt, Addr cfgOffset, uint8_t *cfg) 4319832SN/A{ 4329832SN/A const unsigned size(pkt->getSize()); 4339832SN/A 4349832SN/A if (cfgOffset + size > configSize) 4359832SN/A panic("Config write out of bounds.\n"); 4369832SN/A 4379832SN/A pkt->makeResponse(); 4389832SN/A pkt->writeData((uint8_t *)cfg + cfgOffset); 4399832SN/A} 4409832SN/A 4419832SN/A 4429832SN/Aconst VirtQueue & 4439832SN/AVirtIODeviceBase::getCurrentQueue() const 4449832SN/A{ 44510047SN/A if (_queueSelect >= _queues.size()) 4469832SN/A panic("Guest tried to access non-existing VirtQueue (%i).\n", _queueSelect); 4479832SN/A 4489832SN/A return *_queues[_queueSelect]; 4499838SN/A} 4509838SN/A 4519838SN/AVirtQueue & 4529832SN/AVirtIODeviceBase::getCurrentQueue() 4539832SN/A{ 4549832SN/A if (_queueSelect >= _queues.size()) 4559832SN/A panic("Guest tried to access non-existing VirtQueue (%i).\n", _queueSelect); 4569832SN/A 4579832SN/A return *_queues[_queueSelect]; 4589832SN/A} 4599832SN/A 4609832SN/Avoid 4619832SN/AVirtIODeviceBase::setQueueAddress(uint32_t address) 4629832SN/A{ 4639832SN/A getCurrentQueue().setAddress(address * VirtQueue::ALIGN_SIZE); 4649832SN/A} 4659832SN/A 4669832SN/Auint32_t 4679832SN/AVirtIODeviceBase::getQueueAddress() const 4689832SN/A{ 4699832SN/A Addr address(getCurrentQueue().getAddress()); 4709832SN/A assert(!(address & ((1 >> VirtQueue::ALIGN_BITS) - 1))); 4719832SN/A return address >> VirtQueue::ALIGN_BITS; 4729243SN/A} 4739832SN/A 4749832SN/Avoid 4759832SN/AVirtIODeviceBase::registerQueue(VirtQueue &queue) 4769966SN/A{ 4779243SN/A _queues.push_back(&queue); 4789832SN/A} 4799832SN/A