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