pci.cc revision 11930
13101Sstever@eecs.umich.edu/*
23101Sstever@eecs.umich.edu * Copyright (c) 2014 ARM Limited
33101Sstever@eecs.umich.edu * All rights reserved
43101Sstever@eecs.umich.edu *
53101Sstever@eecs.umich.edu * The license below extends only to copyright in the software and shall
63101Sstever@eecs.umich.edu * not be construed as granting a license to any other intellectual
73101Sstever@eecs.umich.edu * property including but not limited to intellectual property relating
83101Sstever@eecs.umich.edu * to a hardware implementation of the functionality of the software
93101Sstever@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
103101Sstever@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
113101Sstever@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
123101Sstever@eecs.umich.edu * modified or unmodified, in source code or in binary form.
133101Sstever@eecs.umich.edu *
143101Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
153101Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are
163101Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright
173101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
183101Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
193101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
203101Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution;
213101Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its
223101Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from
233101Sstever@eecs.umich.edu * this software without specific prior written permission.
243101Sstever@eecs.umich.edu *
253101Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
263101Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
273101Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
283101Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
293101Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
303101Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
313101Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
323101Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
333101Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
343101Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
353101Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
363101Sstever@eecs.umich.edu *
373101Sstever@eecs.umich.edu * Authors: Andreas Sandberg
383101Sstever@eecs.umich.edu */
393101Sstever@eecs.umich.edu
403101Sstever@eecs.umich.edu#include "dev/virtio/pci.hh"
413101Sstever@eecs.umich.edu
423101Sstever@eecs.umich.edu#include "debug/VIOIface.hh"
433101Sstever@eecs.umich.edu#include "mem/packet_access.hh"
443101Sstever@eecs.umich.edu#include "params/PciVirtIO.hh"
453101Sstever@eecs.umich.edu
463101Sstever@eecs.umich.eduPciVirtIO::PciVirtIO(const Params *params)
473885Sbinkertn@umich.edu    : PciDevice(params), queueNotify(0), interruptDeliveryPending(false),
483885Sbinkertn@umich.edu      vio(*params->vio), callbackKick(this)
494762Snate@binkert.org{
503885Sbinkertn@umich.edu    // Override the subsystem ID with the device ID from VirtIO
513885Sbinkertn@umich.edu    config.subsystemID = htole(vio.deviceId);
527528Ssteve.reinhardt@amd.com    BARSize[0] = BAR0_SIZE_BASE + vio.configSize;
533885Sbinkertn@umich.edu
544380Sbinkertn@umich.edu    vio.registerKickCallback(&callbackKick);
554167Sbinkertn@umich.edu}
563102Sstever@eecs.umich.edu
573101Sstever@eecs.umich.eduPciVirtIO::~PciVirtIO()
584762Snate@binkert.org{
594762Snate@binkert.org}
604762Snate@binkert.org
614762Snate@binkert.orgTick
624762Snate@binkert.orgPciVirtIO::read(PacketPtr pkt)
634762Snate@binkert.org{
644762Snate@binkert.org    const unsigned M5_VAR_USED size(pkt->getSize());
654762Snate@binkert.org    int bar;
664762Snate@binkert.org    Addr offset;
675033Smilesck@eecs.umich.edu    if (!getBAR(pkt->getAddr(), bar, offset))
685033Smilesck@eecs.umich.edu        panic("Invalid PCI memory access to unmapped memory.\n");
695033Smilesck@eecs.umich.edu    assert(bar == 0);
705033Smilesck@eecs.umich.edu
715033Smilesck@eecs.umich.edu    DPRINTF(VIOIface, "Reading offset 0x%x [len: %i]\n", offset, size);
725033Smilesck@eecs.umich.edu
735033Smilesck@eecs.umich.edu    // Forward device configuration writes to the device VirtIO model
745033Smilesck@eecs.umich.edu    if (offset >= OFF_VIO_DEVICE) {
755033Smilesck@eecs.umich.edu        vio.readConfig(pkt, offset - OFF_VIO_DEVICE);
765033Smilesck@eecs.umich.edu        return 0;
773101Sstever@eecs.umich.edu    }
783101Sstever@eecs.umich.edu
793101Sstever@eecs.umich.edu    pkt->makeResponse();
805033Smilesck@eecs.umich.edu
813101Sstever@eecs.umich.edu    switch(offset) {
823101Sstever@eecs.umich.edu      case OFF_DEVICE_FEATURES:
833101Sstever@eecs.umich.edu        DPRINTF(VIOIface, "   DEVICE_FEATURES request\n");
843101Sstever@eecs.umich.edu        assert(size == sizeof(uint32_t));
853101Sstever@eecs.umich.edu        pkt->set<uint32_t>(vio.deviceFeatures);
863101Sstever@eecs.umich.edu        break;
873101Sstever@eecs.umich.edu
883101Sstever@eecs.umich.edu      case OFF_GUEST_FEATURES:
893101Sstever@eecs.umich.edu        DPRINTF(VIOIface, "   GUEST_FEATURES request\n");
903101Sstever@eecs.umich.edu        assert(size == sizeof(uint32_t));
913101Sstever@eecs.umich.edu        pkt->set<uint32_t>(vio.getGuestFeatures());
923101Sstever@eecs.umich.edu        break;
933101Sstever@eecs.umich.edu
943101Sstever@eecs.umich.edu      case OFF_QUEUE_ADDRESS:
953101Sstever@eecs.umich.edu        DPRINTF(VIOIface, "   QUEUE_ADDRESS request\n");
963101Sstever@eecs.umich.edu        assert(size == sizeof(uint32_t));
976656Snate@binkert.org        pkt->set<uint32_t>(vio.getQueueAddress());
986656Snate@binkert.org        break;
993101Sstever@eecs.umich.edu
1003101Sstever@eecs.umich.edu      case OFF_QUEUE_SIZE:
1013101Sstever@eecs.umich.edu        DPRINTF(VIOIface, "   QUEUE_SIZE request\n");
1023101Sstever@eecs.umich.edu        assert(size == sizeof(uint16_t));
1033101Sstever@eecs.umich.edu        pkt->set<uint16_t>(vio.getQueueSize());
1043101Sstever@eecs.umich.edu        break;
1053101Sstever@eecs.umich.edu
1063101Sstever@eecs.umich.edu      case OFF_QUEUE_SELECT:
1073101Sstever@eecs.umich.edu        DPRINTF(VIOIface, "   QUEUE_SELECT\n");
1083101Sstever@eecs.umich.edu        assert(size == sizeof(uint16_t));
1093101Sstever@eecs.umich.edu        pkt->set<uint16_t>(vio.getQueueSelect());
1103101Sstever@eecs.umich.edu        break;
1113101Sstever@eecs.umich.edu
1123101Sstever@eecs.umich.edu      case OFF_QUEUE_NOTIFY:
1133101Sstever@eecs.umich.edu        DPRINTF(VIOIface, "   QUEUE_NOTIFY request\n");
1143101Sstever@eecs.umich.edu        assert(size == sizeof(uint16_t));
1153101Sstever@eecs.umich.edu        pkt->set<uint16_t>(queueNotify);
1163101Sstever@eecs.umich.edu        break;
1173101Sstever@eecs.umich.edu
1183101Sstever@eecs.umich.edu      case OFF_DEVICE_STATUS:
1193101Sstever@eecs.umich.edu        DPRINTF(VIOIface, "   DEVICE_STATUS request\n");
1203101Sstever@eecs.umich.edu        assert(size == sizeof(uint8_t));
1213101Sstever@eecs.umich.edu        pkt->set<uint8_t>(vio.getDeviceStatus());
1223101Sstever@eecs.umich.edu        break;
1233101Sstever@eecs.umich.edu
1243101Sstever@eecs.umich.edu      case OFF_ISR_STATUS: {
1253101Sstever@eecs.umich.edu          DPRINTF(VIOIface, "   ISR_STATUS\n");
1263101Sstever@eecs.umich.edu          assert(size == sizeof(uint8_t));
1273101Sstever@eecs.umich.edu          const uint8_t isr_status(interruptDeliveryPending ? 1 : 0);
1283101Sstever@eecs.umich.edu          if (interruptDeliveryPending) {
1293101Sstever@eecs.umich.edu              interruptDeliveryPending = false;
1303101Sstever@eecs.umich.edu              intrClear();
1313101Sstever@eecs.umich.edu          }
1325033Smilesck@eecs.umich.edu          pkt->set<uint8_t>(isr_status);
1336656Snate@binkert.org      } break;
1345033Smilesck@eecs.umich.edu
1355033Smilesck@eecs.umich.edu      default:
1365033Smilesck@eecs.umich.edu        panic("Unhandled read offset (0x%x)\n", offset);
1373101Sstever@eecs.umich.edu    }
1383101Sstever@eecs.umich.edu
1393101Sstever@eecs.umich.edu    return 0;
1403101Sstever@eecs.umich.edu}
1413101Sstever@eecs.umich.edu
1423101Sstever@eecs.umich.eduTick
1433101Sstever@eecs.umich.eduPciVirtIO::write(PacketPtr pkt)
1443101Sstever@eecs.umich.edu{
1453101Sstever@eecs.umich.edu    const unsigned M5_VAR_USED size(pkt->getSize());
1463101Sstever@eecs.umich.edu    int bar;
1473101Sstever@eecs.umich.edu    Addr offset;
1483101Sstever@eecs.umich.edu    if (!getBAR(pkt->getAddr(), bar, offset))
1493101Sstever@eecs.umich.edu        panic("Invalid PCI memory access to unmapped memory.\n");
1503102Sstever@eecs.umich.edu    assert(bar == 0);
1513101Sstever@eecs.umich.edu
1523101Sstever@eecs.umich.edu    DPRINTF(VIOIface, "Writing offset 0x%x [len: %i]\n", offset, size);
1533101Sstever@eecs.umich.edu
1543101Sstever@eecs.umich.edu    // Forward device configuration writes to the device VirtIO model
1553101Sstever@eecs.umich.edu    if (offset >= OFF_VIO_DEVICE) {
1563101Sstever@eecs.umich.edu        vio.writeConfig(pkt, offset - OFF_VIO_DEVICE);
1573101Sstever@eecs.umich.edu        return 0;
1583101Sstever@eecs.umich.edu    }
1593101Sstever@eecs.umich.edu
1603101Sstever@eecs.umich.edu    pkt->makeResponse();
1613101Sstever@eecs.umich.edu
1623101Sstever@eecs.umich.edu    switch(offset) {
1633101Sstever@eecs.umich.edu      case OFF_DEVICE_FEATURES:
1643101Sstever@eecs.umich.edu        warn("Guest tried to write device features.");
1653101Sstever@eecs.umich.edu        break;
1663101Sstever@eecs.umich.edu
1673101Sstever@eecs.umich.edu      case OFF_GUEST_FEATURES:
1685033Smilesck@eecs.umich.edu        DPRINTF(VIOIface, "   WRITE GUEST_FEATURES request\n");
1695475Snate@binkert.org        assert(size == sizeof(uint32_t));
1705475Snate@binkert.org        vio.setGuestFeatures(pkt->get<uint32_t>());
1715475Snate@binkert.org        break;
1725475Snate@binkert.org
1733101Sstever@eecs.umich.edu      case OFF_QUEUE_ADDRESS:
1743101Sstever@eecs.umich.edu        DPRINTF(VIOIface, "   WRITE QUEUE_ADDRESS\n");
1753101Sstever@eecs.umich.edu        assert(size == sizeof(uint32_t));
1764762Snate@binkert.org        vio.setQueueAddress(pkt->get<uint32_t>());
1774762Snate@binkert.org        break;
1784762Snate@binkert.org
1793101Sstever@eecs.umich.edu      case OFF_QUEUE_SIZE:
1803101Sstever@eecs.umich.edu        panic("Guest tried to write queue size.");
1813101Sstever@eecs.umich.edu        break;
1827528Ssteve.reinhardt@amd.com
1837528Ssteve.reinhardt@amd.com      case OFF_QUEUE_SELECT:
1847528Ssteve.reinhardt@amd.com        DPRINTF(VIOIface, "   WRITE QUEUE_SELECT\n");
1857528Ssteve.reinhardt@amd.com        assert(size == sizeof(uint16_t));
1867528Ssteve.reinhardt@amd.com        vio.setQueueSelect(pkt->get<uint16_t>());
1877528Ssteve.reinhardt@amd.com        break;
1883101Sstever@eecs.umich.edu
1897528Ssteve.reinhardt@amd.com      case OFF_QUEUE_NOTIFY:
1907528Ssteve.reinhardt@amd.com        DPRINTF(VIOIface, "   WRITE QUEUE_NOTIFY\n");
1917528Ssteve.reinhardt@amd.com        assert(size == sizeof(uint16_t));
1927528Ssteve.reinhardt@amd.com        queueNotify = pkt->get<uint16_t>();
1937528Ssteve.reinhardt@amd.com        vio.onNotify(queueNotify);
1947528Ssteve.reinhardt@amd.com        break;
1957528Ssteve.reinhardt@amd.com
1967528Ssteve.reinhardt@amd.com      case OFF_DEVICE_STATUS: {
1977528Ssteve.reinhardt@amd.com          assert(size == sizeof(uint8_t));
1987528Ssteve.reinhardt@amd.com          uint8_t status(pkt->get<uint8_t>());
1997528Ssteve.reinhardt@amd.com          DPRINTF(VIOIface, "VirtIO set status: 0x%x\n", status);
2007528Ssteve.reinhardt@amd.com          vio.setDeviceStatus(status);
2017528Ssteve.reinhardt@amd.com      } break;
2027528Ssteve.reinhardt@amd.com
2037528Ssteve.reinhardt@amd.com      case OFF_ISR_STATUS:
2047528Ssteve.reinhardt@amd.com        warn("Guest tried to write ISR status.");
2057528Ssteve.reinhardt@amd.com        break;
2067528Ssteve.reinhardt@amd.com
2077528Ssteve.reinhardt@amd.com      default:
2087528Ssteve.reinhardt@amd.com        panic("Unhandled read offset (0x%x)\n", offset);
2097528Ssteve.reinhardt@amd.com    }
2107528Ssteve.reinhardt@amd.com
2117528Ssteve.reinhardt@amd.com    return 0;
2127528Ssteve.reinhardt@amd.com}
2137528Ssteve.reinhardt@amd.com
2147528Ssteve.reinhardt@amd.comvoid
2157528Ssteve.reinhardt@amd.comPciVirtIO::kick()
2167528Ssteve.reinhardt@amd.com{
2177528Ssteve.reinhardt@amd.com    DPRINTF(VIOIface, "kick(): Sending interrupt...\n");
2183101Sstever@eecs.umich.edu    interruptDeliveryPending = true;
2193101Sstever@eecs.umich.edu    intrPost();
2206656Snate@binkert.org}
2216656Snate@binkert.org
2223101Sstever@eecs.umich.eduPciVirtIO *
2233101Sstever@eecs.umich.eduPciVirtIOParams::create()
2243101Sstever@eecs.umich.edu{
2253101Sstever@eecs.umich.edu    return new PciVirtIO(this);
2263101Sstever@eecs.umich.edu}
2273101Sstever@eecs.umich.edu