vio_mmio.cc revision 13230
112740Sandreas.sandberg@arm.com/* 212740Sandreas.sandberg@arm.com * Copyright (c) 2016-2018 ARM Limited 312740Sandreas.sandberg@arm.com * All rights reserved 412740Sandreas.sandberg@arm.com * 512740Sandreas.sandberg@arm.com * The license below extends only to copyright in the software and shall 612740Sandreas.sandberg@arm.com * not be construed as granting a license to any other intellectual 712740Sandreas.sandberg@arm.com * property including but not limited to intellectual property relating 812740Sandreas.sandberg@arm.com * to a hardware implementation of the functionality of the software 912740Sandreas.sandberg@arm.com * licensed hereunder. You may use the software subject to the license 1012740Sandreas.sandberg@arm.com * terms below provided that you ensure that this notice is replicated 1112740Sandreas.sandberg@arm.com * unmodified and in its entirety in all distributions of the software, 1212740Sandreas.sandberg@arm.com * modified or unmodified, in source code or in binary form. 1312740Sandreas.sandberg@arm.com * 1412740Sandreas.sandberg@arm.com * Redistribution and use in source and binary forms, with or without 1512740Sandreas.sandberg@arm.com * modification, are permitted provided that the following conditions are 1612740Sandreas.sandberg@arm.com * met: redistributions of source code must retain the above copyright 1712740Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer; 1812740Sandreas.sandberg@arm.com * redistributions in binary form must reproduce the above copyright 1912740Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer in the 2012740Sandreas.sandberg@arm.com * documentation and/or other materials provided with the distribution; 2112740Sandreas.sandberg@arm.com * neither the name of the copyright holders nor the names of its 2212740Sandreas.sandberg@arm.com * contributors may be used to endorse or promote products derived from 2312740Sandreas.sandberg@arm.com * this software without specific prior written permission. 2412740Sandreas.sandberg@arm.com * 2512740Sandreas.sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 2612740Sandreas.sandberg@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 2712740Sandreas.sandberg@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 2812740Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2912740Sandreas.sandberg@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3012740Sandreas.sandberg@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 3112740Sandreas.sandberg@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3212740Sandreas.sandberg@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3312740Sandreas.sandberg@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3412740Sandreas.sandberg@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 3512740Sandreas.sandberg@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3612740Sandreas.sandberg@arm.com * 3712740Sandreas.sandberg@arm.com * Authors: Andreas Sandberg 3812740Sandreas.sandberg@arm.com */ 3912740Sandreas.sandberg@arm.com 4012740Sandreas.sandberg@arm.com#include "dev/arm/vio_mmio.hh" 4112740Sandreas.sandberg@arm.com 4212740Sandreas.sandberg@arm.com#include "debug/VIOIface.hh" 4312740Sandreas.sandberg@arm.com#include "dev/arm/base_gic.hh" 4412740Sandreas.sandberg@arm.com#include "mem/packet_access.hh" 4512740Sandreas.sandberg@arm.com#include "params/MmioVirtIO.hh" 4612740Sandreas.sandberg@arm.com 4712740Sandreas.sandberg@arm.comMmioVirtIO::MmioVirtIO(const MmioVirtIOParams *params) 4812740Sandreas.sandberg@arm.com : BasicPioDevice(params, params->pio_size), 4912740Sandreas.sandberg@arm.com hostFeaturesSelect(0), guestFeaturesSelect(0), pageSize(0), 5012740Sandreas.sandberg@arm.com interruptStatus(0), 5112974Sgiacomo.travaglini@arm.com callbackKick(this), vio(*params->vio), 5212974Sgiacomo.travaglini@arm.com interrupt(params->interrupt->get()) 5312740Sandreas.sandberg@arm.com{ 5412740Sandreas.sandberg@arm.com fatal_if(!interrupt, "No MMIO VirtIO interrupt specified\n"); 5512740Sandreas.sandberg@arm.com 5612740Sandreas.sandberg@arm.com vio.registerKickCallback(&callbackKick); 5712740Sandreas.sandberg@arm.com} 5812740Sandreas.sandberg@arm.com 5912740Sandreas.sandberg@arm.comMmioVirtIO::~MmioVirtIO() 6012740Sandreas.sandberg@arm.com{ 6112740Sandreas.sandberg@arm.com} 6212740Sandreas.sandberg@arm.com 6312740Sandreas.sandberg@arm.comTick 6412740Sandreas.sandberg@arm.comMmioVirtIO::read(PacketPtr pkt) 6512740Sandreas.sandberg@arm.com{ 6612740Sandreas.sandberg@arm.com const Addr offset = pkt->getAddr() - pioAddr; 6712740Sandreas.sandberg@arm.com const unsigned size(pkt->getSize()); 6812740Sandreas.sandberg@arm.com 6912740Sandreas.sandberg@arm.com DPRINTF(VIOIface, "Reading %u bytes @ 0x%x:\n", size, offset); 7012740Sandreas.sandberg@arm.com 7112740Sandreas.sandberg@arm.com // Forward device configuration writes to the device VirtIO model 7212740Sandreas.sandberg@arm.com if (offset >= OFF_CONFIG) { 7312740Sandreas.sandberg@arm.com vio.readConfig(pkt, offset - OFF_CONFIG); 7412740Sandreas.sandberg@arm.com return 0; 7512740Sandreas.sandberg@arm.com } 7612740Sandreas.sandberg@arm.com 7712740Sandreas.sandberg@arm.com panic_if(size != 4, "Unexpected read size: %u\n", size); 7812740Sandreas.sandberg@arm.com 7912740Sandreas.sandberg@arm.com const uint32_t value = read(offset); 8012740Sandreas.sandberg@arm.com DPRINTF(VIOIface, " value: 0x%x\n", value); 8112740Sandreas.sandberg@arm.com pkt->makeResponse(); 8213230Sgabeblack@google.com pkt->setLE<uint32_t>(value); 8312740Sandreas.sandberg@arm.com 8412740Sandreas.sandberg@arm.com return 0; 8512740Sandreas.sandberg@arm.com} 8612740Sandreas.sandberg@arm.com 8712740Sandreas.sandberg@arm.comuint32_t 8812740Sandreas.sandberg@arm.comMmioVirtIO::read(Addr offset) 8912740Sandreas.sandberg@arm.com{ 9012740Sandreas.sandberg@arm.com switch(offset) { 9112740Sandreas.sandberg@arm.com case OFF_MAGIC: 9212740Sandreas.sandberg@arm.com return MAGIC; 9312740Sandreas.sandberg@arm.com 9412740Sandreas.sandberg@arm.com case OFF_VERSION: 9512740Sandreas.sandberg@arm.com return VERSION; 9612740Sandreas.sandberg@arm.com 9712740Sandreas.sandberg@arm.com case OFF_DEVICE_ID: 9812740Sandreas.sandberg@arm.com return vio.deviceId; 9912740Sandreas.sandberg@arm.com 10012740Sandreas.sandberg@arm.com case OFF_VENDOR_ID: 10112740Sandreas.sandberg@arm.com return VENDOR_ID; 10212740Sandreas.sandberg@arm.com 10312740Sandreas.sandberg@arm.com case OFF_HOST_FEATURES: 10412740Sandreas.sandberg@arm.com // We only implement 32 bits of this register 10512740Sandreas.sandberg@arm.com if (hostFeaturesSelect == 0) 10612740Sandreas.sandberg@arm.com return vio.deviceFeatures; 10712740Sandreas.sandberg@arm.com else 10812740Sandreas.sandberg@arm.com return 0; 10912740Sandreas.sandberg@arm.com 11012740Sandreas.sandberg@arm.com case OFF_HOST_FEATURES_SELECT: 11112740Sandreas.sandberg@arm.com return hostFeaturesSelect; 11212740Sandreas.sandberg@arm.com 11312740Sandreas.sandberg@arm.com case OFF_GUEST_FEATURES: 11412740Sandreas.sandberg@arm.com // We only implement 32 bits of this register 11512740Sandreas.sandberg@arm.com if (guestFeaturesSelect == 0) 11612740Sandreas.sandberg@arm.com return vio.getGuestFeatures(); 11712740Sandreas.sandberg@arm.com else 11812740Sandreas.sandberg@arm.com return 0; 11912740Sandreas.sandberg@arm.com 12012740Sandreas.sandberg@arm.com case OFF_GUEST_FEATURES_SELECT: 12112740Sandreas.sandberg@arm.com return hostFeaturesSelect; 12212740Sandreas.sandberg@arm.com 12312740Sandreas.sandberg@arm.com case OFF_GUEST_PAGE_SIZE: 12412740Sandreas.sandberg@arm.com return pageSize; 12512740Sandreas.sandberg@arm.com 12612740Sandreas.sandberg@arm.com case OFF_QUEUE_SELECT: 12712740Sandreas.sandberg@arm.com return vio.getQueueSelect(); 12812740Sandreas.sandberg@arm.com 12912740Sandreas.sandberg@arm.com case OFF_QUEUE_NUM_MAX: 13012740Sandreas.sandberg@arm.com return vio.getQueueSize(); 13112740Sandreas.sandberg@arm.com 13212740Sandreas.sandberg@arm.com case OFF_QUEUE_NUM: 13312740Sandreas.sandberg@arm.com // TODO: We don't support queue resizing, so ignore this for now. 13412740Sandreas.sandberg@arm.com return vio.getQueueSize(); 13512740Sandreas.sandberg@arm.com 13612740Sandreas.sandberg@arm.com case OFF_QUEUE_ALIGN: 13712740Sandreas.sandberg@arm.com // TODO: Implement this once we support other alignment sizes 13812740Sandreas.sandberg@arm.com return VirtQueue::ALIGN_SIZE; 13912740Sandreas.sandberg@arm.com 14012740Sandreas.sandberg@arm.com case OFF_QUEUE_PFN: 14112740Sandreas.sandberg@arm.com return vio.getQueueAddress(); 14212740Sandreas.sandberg@arm.com 14312740Sandreas.sandberg@arm.com case OFF_INTERRUPT_STATUS: 14412740Sandreas.sandberg@arm.com return interruptStatus; 14512740Sandreas.sandberg@arm.com 14612740Sandreas.sandberg@arm.com case OFF_STATUS: 14712740Sandreas.sandberg@arm.com return vio.getDeviceStatus(); 14812740Sandreas.sandberg@arm.com 14912740Sandreas.sandberg@arm.com // Write-only registers 15012740Sandreas.sandberg@arm.com case OFF_QUEUE_NOTIFY: 15112740Sandreas.sandberg@arm.com case OFF_INTERRUPT_ACK: 15212740Sandreas.sandberg@arm.com warn("Guest is trying to read to write-only register 0x%\n", 15312740Sandreas.sandberg@arm.com offset); 15412740Sandreas.sandberg@arm.com return 0; 15512740Sandreas.sandberg@arm.com 15612740Sandreas.sandberg@arm.com default: 15712740Sandreas.sandberg@arm.com panic("Unhandled read offset (0x%x)\n", offset); 15812740Sandreas.sandberg@arm.com } 15912740Sandreas.sandberg@arm.com} 16012740Sandreas.sandberg@arm.com 16112740Sandreas.sandberg@arm.comTick 16212740Sandreas.sandberg@arm.comMmioVirtIO::write(PacketPtr pkt) 16312740Sandreas.sandberg@arm.com{ 16412740Sandreas.sandberg@arm.com const Addr offset = pkt->getAddr() - pioAddr; 16512740Sandreas.sandberg@arm.com const unsigned size(pkt->getSize()); 16612740Sandreas.sandberg@arm.com 16712740Sandreas.sandberg@arm.com DPRINTF(VIOIface, "Writing %u bytes @ 0x%x:\n", size, offset); 16812740Sandreas.sandberg@arm.com 16912740Sandreas.sandberg@arm.com // Forward device configuration writes to the device VirtIO model 17012740Sandreas.sandberg@arm.com if (offset >= OFF_CONFIG) { 17112740Sandreas.sandberg@arm.com vio.writeConfig(pkt, offset - OFF_CONFIG); 17212740Sandreas.sandberg@arm.com return 0; 17312740Sandreas.sandberg@arm.com } 17412740Sandreas.sandberg@arm.com 17512740Sandreas.sandberg@arm.com panic_if(size != 4, "Unexpected write size @ 0x%x: %u\n", offset, size); 17613230Sgabeblack@google.com DPRINTF(VIOIface, " value: 0x%x\n", pkt->getLE<uint32_t>()); 17712740Sandreas.sandberg@arm.com pkt->makeResponse(); 17813230Sgabeblack@google.com write(offset, pkt->getLE<uint32_t>()); 17912740Sandreas.sandberg@arm.com return 0; 18012740Sandreas.sandberg@arm.com} 18112740Sandreas.sandberg@arm.com 18212740Sandreas.sandberg@arm.comvoid 18312740Sandreas.sandberg@arm.comMmioVirtIO::write(Addr offset, uint32_t value) 18412740Sandreas.sandberg@arm.com{ 18512740Sandreas.sandberg@arm.com switch(offset) { 18612740Sandreas.sandberg@arm.com case OFF_HOST_FEATURES_SELECT: 18712740Sandreas.sandberg@arm.com hostFeaturesSelect = value; 18812740Sandreas.sandberg@arm.com return; 18912740Sandreas.sandberg@arm.com 19012740Sandreas.sandberg@arm.com case OFF_GUEST_FEATURES: 19112740Sandreas.sandberg@arm.com if (guestFeaturesSelect == 0) { 19212740Sandreas.sandberg@arm.com vio.setGuestFeatures(value); 19312740Sandreas.sandberg@arm.com } else if (value != 0) { 19412740Sandreas.sandberg@arm.com warn("Setting unimplemented guest features register %u: %u\n", 19512740Sandreas.sandberg@arm.com guestFeaturesSelect, value); 19612740Sandreas.sandberg@arm.com } 19712740Sandreas.sandberg@arm.com return; 19812740Sandreas.sandberg@arm.com 19912740Sandreas.sandberg@arm.com case OFF_GUEST_FEATURES_SELECT: 20012740Sandreas.sandberg@arm.com guestFeaturesSelect = value; 20112740Sandreas.sandberg@arm.com return; 20212740Sandreas.sandberg@arm.com 20312740Sandreas.sandberg@arm.com case OFF_GUEST_PAGE_SIZE: 20412740Sandreas.sandberg@arm.com // TODO: We only support 4096 byte pages at the moment 20512740Sandreas.sandberg@arm.com panic_if(value != VirtQueue::ALIGN_SIZE, 20612740Sandreas.sandberg@arm.com "Unhandled VirtIO page size: %u", value); 20712740Sandreas.sandberg@arm.com pageSize = value; 20812740Sandreas.sandberg@arm.com return; 20912740Sandreas.sandberg@arm.com 21012740Sandreas.sandberg@arm.com case OFF_QUEUE_SELECT: 21112740Sandreas.sandberg@arm.com vio.setQueueSelect(value); 21212740Sandreas.sandberg@arm.com return; 21312740Sandreas.sandberg@arm.com 21412740Sandreas.sandberg@arm.com case OFF_QUEUE_NUM: 21512740Sandreas.sandberg@arm.com // TODO: We don't support queue resizing, so ignore this for now. 21612740Sandreas.sandberg@arm.com warn_once("Ignoring queue resize hint. Requested size: %u\n", value); 21712740Sandreas.sandberg@arm.com return; 21812740Sandreas.sandberg@arm.com 21912740Sandreas.sandberg@arm.com case OFF_QUEUE_ALIGN: 22012740Sandreas.sandberg@arm.com // TODO: We currently only support the hard-coded 4k alignment used 22112740Sandreas.sandberg@arm.com // in legacy VirtIO. 22212740Sandreas.sandberg@arm.com panic_if(value != VirtQueue::ALIGN_SIZE, 22312740Sandreas.sandberg@arm.com "Unhandled VirtIO alignment size: %u", value); 22412740Sandreas.sandberg@arm.com return; 22512740Sandreas.sandberg@arm.com 22612740Sandreas.sandberg@arm.com case OFF_QUEUE_PFN: 22712740Sandreas.sandberg@arm.com vio.setQueueAddress(value); 22812740Sandreas.sandberg@arm.com return; 22912740Sandreas.sandberg@arm.com 23012740Sandreas.sandberg@arm.com case OFF_QUEUE_NOTIFY: 23112740Sandreas.sandberg@arm.com vio.onNotify(value); 23212740Sandreas.sandberg@arm.com return; 23312740Sandreas.sandberg@arm.com 23412740Sandreas.sandberg@arm.com case OFF_INTERRUPT_ACK: 23512740Sandreas.sandberg@arm.com setInterrupts(interruptStatus & (~value)); 23612740Sandreas.sandberg@arm.com return; 23712740Sandreas.sandberg@arm.com 23812740Sandreas.sandberg@arm.com case OFF_STATUS: 23912740Sandreas.sandberg@arm.com panic_if(value > 0xff, "Unexpected status: 0x%x\n", value); 24012740Sandreas.sandberg@arm.com vio.setDeviceStatus(value); 24112740Sandreas.sandberg@arm.com return; 24212740Sandreas.sandberg@arm.com 24312740Sandreas.sandberg@arm.com /* Read-only registers */ 24412740Sandreas.sandberg@arm.com case OFF_MAGIC: 24512740Sandreas.sandberg@arm.com case OFF_VERSION: 24612740Sandreas.sandberg@arm.com case OFF_DEVICE_ID: 24712740Sandreas.sandberg@arm.com case OFF_VENDOR_ID: 24812740Sandreas.sandberg@arm.com case OFF_HOST_FEATURES: 24912740Sandreas.sandberg@arm.com case OFF_QUEUE_NUM_MAX: 25012740Sandreas.sandberg@arm.com case OFF_INTERRUPT_STATUS: 25112740Sandreas.sandberg@arm.com warn("Guest is trying to write to read-only register 0x%\n", 25212740Sandreas.sandberg@arm.com offset); 25312740Sandreas.sandberg@arm.com return; 25412740Sandreas.sandberg@arm.com 25512740Sandreas.sandberg@arm.com default: 25612740Sandreas.sandberg@arm.com panic("Unhandled read offset (0x%x)\n", offset); 25712740Sandreas.sandberg@arm.com } 25812740Sandreas.sandberg@arm.com} 25912740Sandreas.sandberg@arm.com 26012740Sandreas.sandberg@arm.comvoid 26112740Sandreas.sandberg@arm.comMmioVirtIO::kick() 26212740Sandreas.sandberg@arm.com{ 26312740Sandreas.sandberg@arm.com DPRINTF(VIOIface, "kick(): Sending interrupt...\n"); 26412740Sandreas.sandberg@arm.com setInterrupts(interruptStatus | INT_USED_RING); 26512740Sandreas.sandberg@arm.com} 26612740Sandreas.sandberg@arm.com 26712740Sandreas.sandberg@arm.comvoid 26812740Sandreas.sandberg@arm.comMmioVirtIO::setInterrupts(uint32_t value) 26912740Sandreas.sandberg@arm.com{ 27012740Sandreas.sandberg@arm.com const uint32_t old_ints = interruptStatus; 27112740Sandreas.sandberg@arm.com interruptStatus = value; 27212740Sandreas.sandberg@arm.com 27312740Sandreas.sandberg@arm.com if (!old_ints && interruptStatus) { 27412740Sandreas.sandberg@arm.com interrupt->raise(); 27512740Sandreas.sandberg@arm.com } else if (old_ints && !interruptStatus) { 27612740Sandreas.sandberg@arm.com interrupt->clear(); 27712740Sandreas.sandberg@arm.com } 27812740Sandreas.sandberg@arm.com} 27912740Sandreas.sandberg@arm.com 28012740Sandreas.sandberg@arm.com 28112740Sandreas.sandberg@arm.comMmioVirtIO * 28212740Sandreas.sandberg@arm.comMmioVirtIOParams::create() 28312740Sandreas.sandberg@arm.com{ 28412740Sandreas.sandberg@arm.com return new MmioVirtIO(this); 28512740Sandreas.sandberg@arm.com} 286