pci.cc revision 10602
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#include "debug/VIOPci.hh"
4110388SAndreas.Sandberg@ARM.com#include "dev/virtio/pci.hh"
4210388SAndreas.Sandberg@ARM.com#include "mem/packet_access.hh"
4310388SAndreas.Sandberg@ARM.com#include "params/PciVirtIO.hh"
4410388SAndreas.Sandberg@ARM.com
4510388SAndreas.Sandberg@ARM.comPciVirtIO::PciVirtIO(const Params *params)
4610559Sandreas.hansson@arm.com    : PciDevice(params), queueNotify(0), interruptDeliveryPending(false),
4710559Sandreas.hansson@arm.com      vio(*params->vio), callbackKick(this)
4810388SAndreas.Sandberg@ARM.com{
4910388SAndreas.Sandberg@ARM.com    // Override the subsystem ID with the device ID from VirtIO
5010388SAndreas.Sandberg@ARM.com    config.subsystemID = htole(vio.deviceId);
5110388SAndreas.Sandberg@ARM.com    BARSize[0] = BAR0_SIZE_BASE + vio.configSize;
5210388SAndreas.Sandberg@ARM.com
5310388SAndreas.Sandberg@ARM.com    vio.registerKickCallback(&callbackKick);
5410388SAndreas.Sandberg@ARM.com}
5510388SAndreas.Sandberg@ARM.com
5610388SAndreas.Sandberg@ARM.comPciVirtIO::~PciVirtIO()
5710388SAndreas.Sandberg@ARM.com{
5810388SAndreas.Sandberg@ARM.com}
5910388SAndreas.Sandberg@ARM.com
6010388SAndreas.Sandberg@ARM.comTick
6110388SAndreas.Sandberg@ARM.comPciVirtIO::read(PacketPtr pkt)
6210388SAndreas.Sandberg@ARM.com{
6310388SAndreas.Sandberg@ARM.com    const unsigned M5_VAR_USED size(pkt->getSize());
6410388SAndreas.Sandberg@ARM.com    int bar;
6510388SAndreas.Sandberg@ARM.com    Addr offset;
6610388SAndreas.Sandberg@ARM.com    if (!getBAR(pkt->getAddr(), bar, offset))
6710388SAndreas.Sandberg@ARM.com        panic("Invalid PCI memory access to unmapped memory.\n");
6810388SAndreas.Sandberg@ARM.com    assert(bar == 0);
6910388SAndreas.Sandberg@ARM.com
7010388SAndreas.Sandberg@ARM.com    DPRINTF(VIOPci, "Reading offset 0x%x [len: %i]\n", offset, size);
7110388SAndreas.Sandberg@ARM.com
7210388SAndreas.Sandberg@ARM.com    // Forward device configuration writes to the device VirtIO model
7310388SAndreas.Sandberg@ARM.com    if (offset >= OFF_VIO_DEVICE) {
7410388SAndreas.Sandberg@ARM.com        vio.readConfig(pkt, offset - OFF_VIO_DEVICE);
7510388SAndreas.Sandberg@ARM.com        return 0;
7610388SAndreas.Sandberg@ARM.com    }
7710388SAndreas.Sandberg@ARM.com
7810602SAndreas.Sandberg@ARM.com    pkt->makeResponse();
7910602SAndreas.Sandberg@ARM.com
8010388SAndreas.Sandberg@ARM.com    switch(offset) {
8110388SAndreas.Sandberg@ARM.com      case OFF_DEVICE_FEATURES:
8210388SAndreas.Sandberg@ARM.com        DPRINTF(VIOPci, "   DEVICE_FEATURES request\n");
8310388SAndreas.Sandberg@ARM.com        assert(size == sizeof(uint32_t));
8410388SAndreas.Sandberg@ARM.com        pkt->set<uint32_t>(vio.deviceFeatures);
8510388SAndreas.Sandberg@ARM.com        break;
8610388SAndreas.Sandberg@ARM.com
8710388SAndreas.Sandberg@ARM.com      case OFF_GUEST_FEATURES:
8810388SAndreas.Sandberg@ARM.com        DPRINTF(VIOPci, "   GUEST_FEATURES request\n");
8910388SAndreas.Sandberg@ARM.com        assert(size == sizeof(uint32_t));
9010388SAndreas.Sandberg@ARM.com        pkt->set<uint32_t>(vio.getGuestFeatures());
9110388SAndreas.Sandberg@ARM.com        break;
9210388SAndreas.Sandberg@ARM.com
9310388SAndreas.Sandberg@ARM.com      case OFF_QUEUE_ADDRESS:
9410388SAndreas.Sandberg@ARM.com        DPRINTF(VIOPci, "   QUEUE_ADDRESS request\n");
9510388SAndreas.Sandberg@ARM.com        assert(size == sizeof(uint32_t));
9610388SAndreas.Sandberg@ARM.com        pkt->set<uint32_t>(vio.getQueueAddress());
9710388SAndreas.Sandberg@ARM.com        break;
9810388SAndreas.Sandberg@ARM.com
9910388SAndreas.Sandberg@ARM.com      case OFF_QUEUE_SIZE:
10010388SAndreas.Sandberg@ARM.com        DPRINTF(VIOPci, "   QUEUE_SIZE request\n");
10110388SAndreas.Sandberg@ARM.com        assert(size == sizeof(uint16_t));
10210388SAndreas.Sandberg@ARM.com        pkt->set<uint16_t>(vio.getQueueSize());
10310388SAndreas.Sandberg@ARM.com        break;
10410388SAndreas.Sandberg@ARM.com
10510388SAndreas.Sandberg@ARM.com      case OFF_QUEUE_SELECT:
10610388SAndreas.Sandberg@ARM.com        DPRINTF(VIOPci, "   QUEUE_SELECT\n");
10710388SAndreas.Sandberg@ARM.com        assert(size == sizeof(uint16_t));
10810388SAndreas.Sandberg@ARM.com        pkt->set<uint16_t>(vio.getQueueSelect());
10910388SAndreas.Sandberg@ARM.com        break;
11010388SAndreas.Sandberg@ARM.com
11110388SAndreas.Sandberg@ARM.com      case OFF_QUEUE_NOTIFY:
11210388SAndreas.Sandberg@ARM.com        DPRINTF(VIOPci, "   QUEUE_NOTIFY request\n");
11310388SAndreas.Sandberg@ARM.com        assert(size == sizeof(uint16_t));
11410388SAndreas.Sandberg@ARM.com        pkt->set<uint16_t>(queueNotify);
11510388SAndreas.Sandberg@ARM.com        break;
11610388SAndreas.Sandberg@ARM.com
11710388SAndreas.Sandberg@ARM.com      case OFF_DEVICE_STATUS:
11810388SAndreas.Sandberg@ARM.com        DPRINTF(VIOPci, "   DEVICE_STATUS request\n");
11910388SAndreas.Sandberg@ARM.com        assert(size == sizeof(uint8_t));
12010388SAndreas.Sandberg@ARM.com        pkt->set<uint8_t>(vio.getDeviceStatus());
12110388SAndreas.Sandberg@ARM.com        break;
12210388SAndreas.Sandberg@ARM.com
12310388SAndreas.Sandberg@ARM.com      case OFF_ISR_STATUS: {
12410388SAndreas.Sandberg@ARM.com          DPRINTF(VIOPci, "   ISR_STATUS\n");
12510388SAndreas.Sandberg@ARM.com          assert(size == sizeof(uint8_t));
12610388SAndreas.Sandberg@ARM.com          uint8_t isr_status(interruptDeliveryPending ? 1 : 0);
12710388SAndreas.Sandberg@ARM.com          interruptDeliveryPending = false;
12810388SAndreas.Sandberg@ARM.com          pkt->set<uint8_t>(isr_status);
12910388SAndreas.Sandberg@ARM.com      } break;
13010388SAndreas.Sandberg@ARM.com
13110388SAndreas.Sandberg@ARM.com      default:
13210388SAndreas.Sandberg@ARM.com        panic("Unhandled read offset (0x%x)\n", offset);
13310388SAndreas.Sandberg@ARM.com    }
13410388SAndreas.Sandberg@ARM.com
13510388SAndreas.Sandberg@ARM.com    return 0;
13610388SAndreas.Sandberg@ARM.com}
13710388SAndreas.Sandberg@ARM.com
13810388SAndreas.Sandberg@ARM.comTick
13910388SAndreas.Sandberg@ARM.comPciVirtIO::write(PacketPtr pkt)
14010388SAndreas.Sandberg@ARM.com{
14110388SAndreas.Sandberg@ARM.com    const unsigned M5_VAR_USED size(pkt->getSize());
14210388SAndreas.Sandberg@ARM.com    int bar;
14310388SAndreas.Sandberg@ARM.com    Addr offset;
14410388SAndreas.Sandberg@ARM.com    if (!getBAR(pkt->getAddr(), bar, offset))
14510388SAndreas.Sandberg@ARM.com        panic("Invalid PCI memory access to unmapped memory.\n");
14610388SAndreas.Sandberg@ARM.com    assert(bar == 0);
14710388SAndreas.Sandberg@ARM.com
14810388SAndreas.Sandberg@ARM.com    DPRINTF(VIOPci, "Writing offset 0x%x [len: %i]\n", offset, size);
14910388SAndreas.Sandberg@ARM.com
15010388SAndreas.Sandberg@ARM.com    // Forward device configuration writes to the device VirtIO model
15110388SAndreas.Sandberg@ARM.com    if (offset >= OFF_VIO_DEVICE) {
15210388SAndreas.Sandberg@ARM.com        vio.writeConfig(pkt, offset - OFF_VIO_DEVICE);
15310388SAndreas.Sandberg@ARM.com        return 0;
15410388SAndreas.Sandberg@ARM.com    }
15510388SAndreas.Sandberg@ARM.com
15610602SAndreas.Sandberg@ARM.com    pkt->makeResponse();
15710602SAndreas.Sandberg@ARM.com
15810388SAndreas.Sandberg@ARM.com    switch(offset) {
15910388SAndreas.Sandberg@ARM.com      case OFF_DEVICE_FEATURES:
16010388SAndreas.Sandberg@ARM.com        warn("Guest tried to write device features.");
16110388SAndreas.Sandberg@ARM.com        break;
16210388SAndreas.Sandberg@ARM.com
16310388SAndreas.Sandberg@ARM.com      case OFF_GUEST_FEATURES:
16410388SAndreas.Sandberg@ARM.com        DPRINTF(VIOPci, "   WRITE GUEST_FEATURES request\n");
16510388SAndreas.Sandberg@ARM.com        assert(size == sizeof(uint32_t));
16610388SAndreas.Sandberg@ARM.com        vio.setGuestFeatures(pkt->get<uint32_t>());
16710388SAndreas.Sandberg@ARM.com        break;
16810388SAndreas.Sandberg@ARM.com
16910388SAndreas.Sandberg@ARM.com      case OFF_QUEUE_ADDRESS:
17010388SAndreas.Sandberg@ARM.com        DPRINTF(VIOPci, "   WRITE QUEUE_ADDRESS\n");
17110388SAndreas.Sandberg@ARM.com        assert(size == sizeof(uint32_t));
17210388SAndreas.Sandberg@ARM.com        vio.setQueueAddress(pkt->get<uint32_t>());
17310388SAndreas.Sandberg@ARM.com        break;
17410388SAndreas.Sandberg@ARM.com
17510388SAndreas.Sandberg@ARM.com      case OFF_QUEUE_SIZE:
17610388SAndreas.Sandberg@ARM.com        panic("Guest tried to write queue size.");
17710388SAndreas.Sandberg@ARM.com        break;
17810388SAndreas.Sandberg@ARM.com
17910388SAndreas.Sandberg@ARM.com      case OFF_QUEUE_SELECT:
18010388SAndreas.Sandberg@ARM.com        DPRINTF(VIOPci, "   WRITE QUEUE_SELECT\n");
18110388SAndreas.Sandberg@ARM.com        assert(size == sizeof(uint16_t));
18210388SAndreas.Sandberg@ARM.com        vio.setQueueSelect(pkt->get<uint16_t>());
18310388SAndreas.Sandberg@ARM.com        break;
18410388SAndreas.Sandberg@ARM.com
18510388SAndreas.Sandberg@ARM.com      case OFF_QUEUE_NOTIFY:
18610388SAndreas.Sandberg@ARM.com        DPRINTF(VIOPci, "   WRITE QUEUE_NOTIFY\n");
18710388SAndreas.Sandberg@ARM.com        assert(size == sizeof(uint16_t));
18810388SAndreas.Sandberg@ARM.com        queueNotify = pkt->get<uint16_t>();
18910388SAndreas.Sandberg@ARM.com        vio.onNotify(queueNotify);
19010388SAndreas.Sandberg@ARM.com        break;
19110388SAndreas.Sandberg@ARM.com
19210388SAndreas.Sandberg@ARM.com      case OFF_DEVICE_STATUS: {
19310388SAndreas.Sandberg@ARM.com          assert(size == sizeof(uint8_t));
19410388SAndreas.Sandberg@ARM.com          uint8_t status(pkt->get<uint8_t>());
19510388SAndreas.Sandberg@ARM.com          DPRINTF(VIOPci, "VirtIO set status: 0x%x\n", status);
19610388SAndreas.Sandberg@ARM.com          vio.setDeviceStatus(status);
19710388SAndreas.Sandberg@ARM.com      } break;
19810388SAndreas.Sandberg@ARM.com
19910388SAndreas.Sandberg@ARM.com      case OFF_ISR_STATUS:
20010388SAndreas.Sandberg@ARM.com        warn("Guest tried to write ISR status.");
20110388SAndreas.Sandberg@ARM.com        break;
20210388SAndreas.Sandberg@ARM.com
20310388SAndreas.Sandberg@ARM.com      default:
20410388SAndreas.Sandberg@ARM.com        panic("Unhandled read offset (0x%x)\n", offset);
20510388SAndreas.Sandberg@ARM.com    }
20610388SAndreas.Sandberg@ARM.com
20710388SAndreas.Sandberg@ARM.com    return 0;
20810388SAndreas.Sandberg@ARM.com}
20910388SAndreas.Sandberg@ARM.com
21010388SAndreas.Sandberg@ARM.comvoid
21110388SAndreas.Sandberg@ARM.comPciVirtIO::kick()
21210388SAndreas.Sandberg@ARM.com{
21310388SAndreas.Sandberg@ARM.com    DPRINTF(VIOPci, "kick(): Sending interrupt...\n");
21410388SAndreas.Sandberg@ARM.com    interruptDeliveryPending = true;
21510388SAndreas.Sandberg@ARM.com    intrPost();
21610388SAndreas.Sandberg@ARM.com}
21710388SAndreas.Sandberg@ARM.com
21810388SAndreas.Sandberg@ARM.comPciVirtIO *
21910388SAndreas.Sandberg@ARM.comPciVirtIOParams::create()
22010388SAndreas.Sandberg@ARM.com{
22110388SAndreas.Sandberg@ARM.com    return new PciVirtIO(this);
22210388SAndreas.Sandberg@ARM.com}
223