From c5c71a751676a5adecad8ac43ec85b6c4c66ebf0 Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Mon, 7 Nov 2016 18:21:43 +0000 Subject: dev-arm: Add a MMIO transport interface for VirtIO The MMIO interface currently only supports a subset of version 0.9.5 of the VirtIO specification. It has the following known limitations: * The queue size hint (the QUEUE_NUM register) is ignored. * Queue alignment is assumed to be hard-coded to VirtQueue::ALIGN_SIZE (4096 bytes). * Only 4096 byte pages are currently supported. Change-Id: Ifd318f5e5bddab0b6a42d8c8af9ff2fbb477f98b Signed-off-by: Andreas Sandberg Reviewed-by: Nikos Nikoleris Reviewed-by: Rekai Gonzalez Alberquilla Reviewed-on: https://gem5-review.googlesource.com/2326 Reviewed-by: Giacomo Travaglini --- src/dev/arm/SConscript | 2 + src/dev/arm/VirtIOMMIO.py | 63 ++++++++++ src/dev/arm/vio_mmio.cc | 284 ++++++++++++++++++++++++++++++++++++++++++++++ src/dev/arm/vio_mmio.hh | 115 +++++++++++++++++++ 4 files changed, 464 insertions(+) create mode 100644 src/dev/arm/VirtIOMMIO.py create mode 100644 src/dev/arm/vio_mmio.cc create mode 100644 src/dev/arm/vio_mmio.hh diff --git a/src/dev/arm/SConscript b/src/dev/arm/SConscript index ae3ed7194..d45858925 100644 --- a/src/dev/arm/SConscript +++ b/src/dev/arm/SConscript @@ -47,6 +47,7 @@ if env['TARGET_ISA'] == 'arm': SimObject('UFSHostDevice.py') SimObject('EnergyCtrl.py') SimObject('NoMali.py') + SimObject('VirtIOMMIO.py') Source('a9scu.cc') Source('amba_device.cc') @@ -69,6 +70,7 @@ if env['TARGET_ISA'] == 'arm': Source('timer_cpulocal.cc') Source('timer_a9global.cc') Source('vgic.cc') + Source('vio_mmio.cc') Source('ufs_device.cc') Source('energy_ctrl.cc') diff --git a/src/dev/arm/VirtIOMMIO.py b/src/dev/arm/VirtIOMMIO.py new file mode 100644 index 000000000..2c95ef3ce --- /dev/null +++ b/src/dev/arm/VirtIOMMIO.py @@ -0,0 +1,63 @@ +# -*- mode:python -*- + +# Copyright (c) 2014, 2016-2018 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 + +from m5.SimObject import SimObject +from m5.params import * +from m5.proxy import * + +from Device import BasicPioDevice +from Gic import ArmInterruptPin +from VirtIO import VirtIODeviceBase, VirtIODummyDevice + +class MmioVirtIO(BasicPioDevice): + type = 'MmioVirtIO' + cxx_header = 'dev/arm/vio_mmio.hh' + + pio_size = Param.Addr(4096, "IO range") + interrupt = Param.ArmInterruptPin("Interrupt to use for this device") + + vio = Param.VirtIODeviceBase(VirtIODummyDevice(), "VirtIO device") + + def generateDeviceTree(self, state): + node = self.generateBasicPioDeviceNode(state, 'virtio', self.pio_addr, + int(self.pio_size), [ + int(self.interrupt.num), + ]) + node.appendCompatible(["virtio,mmio"]) + yield node diff --git a/src/dev/arm/vio_mmio.cc b/src/dev/arm/vio_mmio.cc new file mode 100644 index 000000000..1dcaf8cd9 --- /dev/null +++ b/src/dev/arm/vio_mmio.cc @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2016-2018 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 "dev/arm/vio_mmio.hh" + +#include "debug/VIOIface.hh" +#include "dev/arm/base_gic.hh" +#include "mem/packet_access.hh" +#include "params/MmioVirtIO.hh" + +MmioVirtIO::MmioVirtIO(const MmioVirtIOParams *params) + : BasicPioDevice(params, params->pio_size), + hostFeaturesSelect(0), guestFeaturesSelect(0), pageSize(0), + interruptStatus(0), + callbackKick(this), vio(*params->vio), interrupt(params->interrupt) +{ + fatal_if(!interrupt, "No MMIO VirtIO interrupt specified\n"); + + vio.registerKickCallback(&callbackKick); +} + +MmioVirtIO::~MmioVirtIO() +{ +} + +Tick +MmioVirtIO::read(PacketPtr pkt) +{ + const Addr offset = pkt->getAddr() - pioAddr; + const unsigned size(pkt->getSize()); + + DPRINTF(VIOIface, "Reading %u bytes @ 0x%x:\n", size, offset); + + // Forward device configuration writes to the device VirtIO model + if (offset >= OFF_CONFIG) { + vio.readConfig(pkt, offset - OFF_CONFIG); + return 0; + } + + panic_if(size != 4, "Unexpected read size: %u\n", size); + + const uint32_t value = read(offset); + DPRINTF(VIOIface, " value: 0x%x\n", value); + pkt->makeResponse(); + pkt->set(value); + + return 0; +} + +uint32_t +MmioVirtIO::read(Addr offset) +{ + switch(offset) { + case OFF_MAGIC: + return MAGIC; + + case OFF_VERSION: + return VERSION; + + case OFF_DEVICE_ID: + return vio.deviceId; + + case OFF_VENDOR_ID: + return VENDOR_ID; + + case OFF_HOST_FEATURES: + // We only implement 32 bits of this register + if (hostFeaturesSelect == 0) + return vio.deviceFeatures; + else + return 0; + + case OFF_HOST_FEATURES_SELECT: + return hostFeaturesSelect; + + case OFF_GUEST_FEATURES: + // We only implement 32 bits of this register + if (guestFeaturesSelect == 0) + return vio.getGuestFeatures(); + else + return 0; + + case OFF_GUEST_FEATURES_SELECT: + return hostFeaturesSelect; + + case OFF_GUEST_PAGE_SIZE: + return pageSize; + + case OFF_QUEUE_SELECT: + return vio.getQueueSelect(); + + case OFF_QUEUE_NUM_MAX: + return vio.getQueueSize(); + + case OFF_QUEUE_NUM: + // TODO: We don't support queue resizing, so ignore this for now. + return vio.getQueueSize(); + + case OFF_QUEUE_ALIGN: + // TODO: Implement this once we support other alignment sizes + return VirtQueue::ALIGN_SIZE; + + case OFF_QUEUE_PFN: + return vio.getQueueAddress(); + + case OFF_INTERRUPT_STATUS: + return interruptStatus; + + case OFF_STATUS: + return vio.getDeviceStatus(); + + // Write-only registers + case OFF_QUEUE_NOTIFY: + case OFF_INTERRUPT_ACK: + warn("Guest is trying to read to write-only register 0x%\n", + offset); + return 0; + + default: + panic("Unhandled read offset (0x%x)\n", offset); + } +} + +Tick +MmioVirtIO::write(PacketPtr pkt) +{ + const Addr offset = pkt->getAddr() - pioAddr; + const unsigned size(pkt->getSize()); + + DPRINTF(VIOIface, "Writing %u bytes @ 0x%x:\n", size, offset); + + // Forward device configuration writes to the device VirtIO model + if (offset >= OFF_CONFIG) { + vio.writeConfig(pkt, offset - OFF_CONFIG); + return 0; + } + + panic_if(size != 4, "Unexpected write size @ 0x%x: %u\n", offset, size); + DPRINTF(VIOIface, " value: 0x%x\n", pkt->get()); + pkt->makeResponse(); + write(offset, pkt->get()); + return 0; +} + +void +MmioVirtIO::write(Addr offset, uint32_t value) +{ + switch(offset) { + case OFF_HOST_FEATURES_SELECT: + hostFeaturesSelect = value; + return; + + case OFF_GUEST_FEATURES: + if (guestFeaturesSelect == 0) { + vio.setGuestFeatures(value); + } else if (value != 0) { + warn("Setting unimplemented guest features register %u: %u\n", + guestFeaturesSelect, value); + } + return; + + case OFF_GUEST_FEATURES_SELECT: + guestFeaturesSelect = value; + return; + + case OFF_GUEST_PAGE_SIZE: + // TODO: We only support 4096 byte pages at the moment + panic_if(value != VirtQueue::ALIGN_SIZE, + "Unhandled VirtIO page size: %u", value); + pageSize = value; + return; + + case OFF_QUEUE_SELECT: + vio.setQueueSelect(value); + return; + + case OFF_QUEUE_NUM: + // TODO: We don't support queue resizing, so ignore this for now. + warn_once("Ignoring queue resize hint. Requested size: %u\n", value); + return; + + case OFF_QUEUE_ALIGN: + // TODO: We currently only support the hard-coded 4k alignment used + // in legacy VirtIO. + panic_if(value != VirtQueue::ALIGN_SIZE, + "Unhandled VirtIO alignment size: %u", value); + return; + + case OFF_QUEUE_PFN: + vio.setQueueAddress(value); + return; + + case OFF_QUEUE_NOTIFY: + vio.onNotify(value); + return; + + case OFF_INTERRUPT_ACK: + setInterrupts(interruptStatus & (~value)); + return; + + case OFF_STATUS: + panic_if(value > 0xff, "Unexpected status: 0x%x\n", value); + vio.setDeviceStatus(value); + return; + + /* Read-only registers */ + case OFF_MAGIC: + case OFF_VERSION: + case OFF_DEVICE_ID: + case OFF_VENDOR_ID: + case OFF_HOST_FEATURES: + case OFF_QUEUE_NUM_MAX: + case OFF_INTERRUPT_STATUS: + warn("Guest is trying to write to read-only register 0x%\n", + offset); + return; + + default: + panic("Unhandled read offset (0x%x)\n", offset); + } +} + +void +MmioVirtIO::kick() +{ + DPRINTF(VIOIface, "kick(): Sending interrupt...\n"); + setInterrupts(interruptStatus | INT_USED_RING); +} + +void +MmioVirtIO::setInterrupts(uint32_t value) +{ + const uint32_t old_ints = interruptStatus; + interruptStatus = value; + + if (!old_ints && interruptStatus) { + interrupt->raise(); + } else if (old_ints && !interruptStatus) { + interrupt->clear(); + } +} + + +MmioVirtIO * +MmioVirtIOParams::create() +{ + return new MmioVirtIO(this); +} diff --git a/src/dev/arm/vio_mmio.hh b/src/dev/arm/vio_mmio.hh new file mode 100644 index 000000000..5a5144bde --- /dev/null +++ b/src/dev/arm/vio_mmio.hh @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2016-2018 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 + */ + +#ifndef __DEV_ARM_VIO_MMIO_HH__ +#define __DEV_ARM_VIO_MMIO_HH__ + +#include "dev/io_device.hh" +#include "dev/virtio/base.hh" + +class ArmInterruptPin; +struct MmioVirtIOParams; + +class MmioVirtIO : public BasicPioDevice +{ + public: + MmioVirtIO(const MmioVirtIOParams *params); + virtual ~MmioVirtIO(); + + protected: // BasicPioDevice + Tick read(PacketPtr pkt) override; + Tick write(PacketPtr pkt) override; + + protected: + /** @{ */ + /** Offsets into VirtIO MMIO space. */ + + enum : Addr { + OFF_MAGIC = 0x00, + OFF_VERSION = 0x04, + OFF_DEVICE_ID = 0x08, + OFF_VENDOR_ID = 0x0C, + OFF_HOST_FEATURES = 0x10, + OFF_HOST_FEATURES_SELECT = 0x14, + OFF_GUEST_FEATURES = 0x20, + OFF_GUEST_FEATURES_SELECT = 0x24, + OFF_GUEST_PAGE_SIZE = 0x28, + OFF_QUEUE_SELECT = 0x30, + OFF_QUEUE_NUM_MAX = 0x34, + OFF_QUEUE_NUM = 0x38, + OFF_QUEUE_ALIGN = 0x3C, + OFF_QUEUE_PFN = 0x40, + OFF_QUEUE_NOTIFY = 0x50, + OFF_INTERRUPT_STATUS = 0x60, + OFF_INTERRUPT_ACK = 0x64, + OFF_STATUS = 0x70, + OFF_CONFIG = 0x100, + }; + + /** @} */ + + enum { + INT_USED_RING = 1 << 0, + INT_CONFIG = 1 << 1, + }; + + static const uint32_t MAGIC = 0x74726976; + static const uint32_t VERSION = 1; + static const uint32_t VENDOR_ID = 0x1AF4; + + + uint32_t read(Addr offset); + void write(Addr offset, uint32_t value); + + void kick(); + void setInterrupts(uint32_t value); + + uint32_t hostFeaturesSelect; + uint32_t guestFeaturesSelect; + uint32_t pageSize; + uint32_t interruptStatus; + + MakeCallback callbackKick; + + protected: // Params + VirtIODeviceBase &vio; + ArmInterruptPin *const interrupt; +}; + +#endif // __DEV_ARM_VIO_MMIO_HH__ -- cgit v1.2.3