summaryrefslogtreecommitdiff
path: root/src/dev/virtio/pci.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/dev/virtio/pci.cc')
-rw-r--r--src/dev/virtio/pci.cc222
1 files changed, 222 insertions, 0 deletions
diff --git a/src/dev/virtio/pci.cc b/src/dev/virtio/pci.cc
new file mode 100644
index 000000000..399590c1b
--- /dev/null
+++ b/src/dev/virtio/pci.cc
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2014 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer;
+ * redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution;
+ * neither the name of the copyright holders nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors: Andreas Sandberg
+ */
+
+#include "debug/VIOPci.hh"
+#include "dev/virtio/pci.hh"
+#include "mem/packet_access.hh"
+#include "params/PciVirtIO.hh"
+
+PciVirtIO::PciVirtIO(const Params *params)
+ : PciDevice(params), vio(*params->vio),
+ callbackKick(this)
+{
+ // Override the subsystem ID with the device ID from VirtIO
+ config.subsystemID = htole(vio.deviceId);
+ BARSize[0] = BAR0_SIZE_BASE + vio.configSize;
+
+ vio.registerKickCallback(&callbackKick);
+}
+
+PciVirtIO::~PciVirtIO()
+{
+}
+
+Tick
+PciVirtIO::read(PacketPtr pkt)
+{
+ const unsigned M5_VAR_USED size(pkt->getSize());
+ int bar;
+ Addr offset;
+ if (!getBAR(pkt->getAddr(), bar, offset))
+ panic("Invalid PCI memory access to unmapped memory.\n");
+ assert(bar == 0);
+
+ DPRINTF(VIOPci, "Reading offset 0x%x [len: %i]\n", offset, size);
+
+ // Forward device configuration writes to the device VirtIO model
+ if (offset >= OFF_VIO_DEVICE) {
+ vio.readConfig(pkt, offset - OFF_VIO_DEVICE);
+ return 0;
+ }
+
+ pkt->allocate();
+
+ switch(offset) {
+ case OFF_DEVICE_FEATURES:
+ DPRINTF(VIOPci, " DEVICE_FEATURES request\n");
+ assert(size == sizeof(uint32_t));
+ pkt->set<uint32_t>(vio.deviceFeatures);
+ break;
+
+ case OFF_GUEST_FEATURES:
+ DPRINTF(VIOPci, " GUEST_FEATURES request\n");
+ assert(size == sizeof(uint32_t));
+ pkt->set<uint32_t>(vio.getGuestFeatures());
+ break;
+
+ case OFF_QUEUE_ADDRESS:
+ DPRINTF(VIOPci, " QUEUE_ADDRESS request\n");
+ assert(size == sizeof(uint32_t));
+ pkt->set<uint32_t>(vio.getQueueAddress());
+ break;
+
+ case OFF_QUEUE_SIZE:
+ DPRINTF(VIOPci, " QUEUE_SIZE request\n");
+ assert(size == sizeof(uint16_t));
+ pkt->set<uint16_t>(vio.getQueueSize());
+ break;
+
+ case OFF_QUEUE_SELECT:
+ DPRINTF(VIOPci, " QUEUE_SELECT\n");
+ assert(size == sizeof(uint16_t));
+ pkt->set<uint16_t>(vio.getQueueSelect());
+ break;
+
+ case OFF_QUEUE_NOTIFY:
+ DPRINTF(VIOPci, " QUEUE_NOTIFY request\n");
+ assert(size == sizeof(uint16_t));
+ pkt->set<uint16_t>(queueNotify);
+ break;
+
+ case OFF_DEVICE_STATUS:
+ DPRINTF(VIOPci, " DEVICE_STATUS request\n");
+ assert(size == sizeof(uint8_t));
+ pkt->set<uint8_t>(vio.getDeviceStatus());
+ break;
+
+ case OFF_ISR_STATUS: {
+ DPRINTF(VIOPci, " ISR_STATUS\n");
+ assert(size == sizeof(uint8_t));
+ uint8_t isr_status(interruptDeliveryPending ? 1 : 0);
+ interruptDeliveryPending = false;
+ pkt->set<uint8_t>(isr_status);
+ } break;
+
+ default:
+ panic("Unhandled read offset (0x%x)\n", offset);
+ }
+
+ return 0;
+}
+
+Tick
+PciVirtIO::write(PacketPtr pkt)
+{
+ const unsigned M5_VAR_USED size(pkt->getSize());
+ int bar;
+ Addr offset;
+ if (!getBAR(pkt->getAddr(), bar, offset))
+ panic("Invalid PCI memory access to unmapped memory.\n");
+ assert(bar == 0);
+
+ DPRINTF(VIOPci, "Writing offset 0x%x [len: %i]\n", offset, size);
+
+ // Forward device configuration writes to the device VirtIO model
+ if (offset >= OFF_VIO_DEVICE) {
+ vio.writeConfig(pkt, offset - OFF_VIO_DEVICE);
+ return 0;
+ }
+
+ pkt->allocate();
+
+ switch(offset) {
+ case OFF_DEVICE_FEATURES:
+ warn("Guest tried to write device features.");
+ break;
+
+ case OFF_GUEST_FEATURES:
+ DPRINTF(VIOPci, " WRITE GUEST_FEATURES request\n");
+ assert(size == sizeof(uint32_t));
+ vio.setGuestFeatures(pkt->get<uint32_t>());
+ break;
+
+ case OFF_QUEUE_ADDRESS:
+ DPRINTF(VIOPci, " WRITE QUEUE_ADDRESS\n");
+ assert(size == sizeof(uint32_t));
+ vio.setQueueAddress(pkt->get<uint32_t>());
+ break;
+
+ case OFF_QUEUE_SIZE:
+ panic("Guest tried to write queue size.");
+ break;
+
+ case OFF_QUEUE_SELECT:
+ DPRINTF(VIOPci, " WRITE QUEUE_SELECT\n");
+ assert(size == sizeof(uint16_t));
+ vio.setQueueSelect(pkt->get<uint16_t>());
+ break;
+
+ case OFF_QUEUE_NOTIFY:
+ DPRINTF(VIOPci, " WRITE QUEUE_NOTIFY\n");
+ assert(size == sizeof(uint16_t));
+ queueNotify = pkt->get<uint16_t>();
+ vio.onNotify(queueNotify);
+ break;
+
+ case OFF_DEVICE_STATUS: {
+ assert(size == sizeof(uint8_t));
+ uint8_t status(pkt->get<uint8_t>());
+ DPRINTF(VIOPci, "VirtIO set status: 0x%x\n", status);
+ vio.setDeviceStatus(status);
+ } break;
+
+ case OFF_ISR_STATUS:
+ warn("Guest tried to write ISR status.");
+ break;
+
+ default:
+ panic("Unhandled read offset (0x%x)\n", offset);
+ }
+
+ return 0;
+}
+
+void
+PciVirtIO::kick()
+{
+ DPRINTF(VIOPci, "kick(): Sending interrupt...\n");
+ interruptDeliveryPending = true;
+ intrPost();
+}
+
+PciVirtIO *
+PciVirtIOParams::create()
+{
+ return new PciVirtIO(this);
+}