vio_mmio.cc revision 12740
1/* 2 * Copyright (c) 2016-2018 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Andreas Sandberg 38 */ 39 40#include "dev/arm/vio_mmio.hh" 41 42#include "debug/VIOIface.hh" 43#include "dev/arm/base_gic.hh" 44#include "mem/packet_access.hh" 45#include "params/MmioVirtIO.hh" 46 47MmioVirtIO::MmioVirtIO(const MmioVirtIOParams *params) 48 : BasicPioDevice(params, params->pio_size), 49 hostFeaturesSelect(0), guestFeaturesSelect(0), pageSize(0), 50 interruptStatus(0), 51 callbackKick(this), vio(*params->vio), interrupt(params->interrupt) 52{ 53 fatal_if(!interrupt, "No MMIO VirtIO interrupt specified\n"); 54 55 vio.registerKickCallback(&callbackKick); 56} 57 58MmioVirtIO::~MmioVirtIO() 59{ 60} 61 62Tick 63MmioVirtIO::read(PacketPtr pkt) 64{ 65 const Addr offset = pkt->getAddr() - pioAddr; 66 const unsigned size(pkt->getSize()); 67 68 DPRINTF(VIOIface, "Reading %u bytes @ 0x%x:\n", size, offset); 69 70 // Forward device configuration writes to the device VirtIO model 71 if (offset >= OFF_CONFIG) { 72 vio.readConfig(pkt, offset - OFF_CONFIG); 73 return 0; 74 } 75 76 panic_if(size != 4, "Unexpected read size: %u\n", size); 77 78 const uint32_t value = read(offset); 79 DPRINTF(VIOIface, " value: 0x%x\n", value); 80 pkt->makeResponse(); 81 pkt->set<uint32_t>(value); 82 83 return 0; 84} 85 86uint32_t 87MmioVirtIO::read(Addr offset) 88{ 89 switch(offset) { 90 case OFF_MAGIC: 91 return MAGIC; 92 93 case OFF_VERSION: 94 return VERSION; 95 96 case OFF_DEVICE_ID: 97 return vio.deviceId; 98 99 case OFF_VENDOR_ID: 100 return VENDOR_ID; 101 102 case OFF_HOST_FEATURES: 103 // We only implement 32 bits of this register 104 if (hostFeaturesSelect == 0) 105 return vio.deviceFeatures; 106 else 107 return 0; 108 109 case OFF_HOST_FEATURES_SELECT: 110 return hostFeaturesSelect; 111 112 case OFF_GUEST_FEATURES: 113 // We only implement 32 bits of this register 114 if (guestFeaturesSelect == 0) 115 return vio.getGuestFeatures(); 116 else 117 return 0; 118 119 case OFF_GUEST_FEATURES_SELECT: 120 return hostFeaturesSelect; 121 122 case OFF_GUEST_PAGE_SIZE: 123 return pageSize; 124 125 case OFF_QUEUE_SELECT: 126 return vio.getQueueSelect(); 127 128 case OFF_QUEUE_NUM_MAX: 129 return vio.getQueueSize(); 130 131 case OFF_QUEUE_NUM: 132 // TODO: We don't support queue resizing, so ignore this for now. 133 return vio.getQueueSize(); 134 135 case OFF_QUEUE_ALIGN: 136 // TODO: Implement this once we support other alignment sizes 137 return VirtQueue::ALIGN_SIZE; 138 139 case OFF_QUEUE_PFN: 140 return vio.getQueueAddress(); 141 142 case OFF_INTERRUPT_STATUS: 143 return interruptStatus; 144 145 case OFF_STATUS: 146 return vio.getDeviceStatus(); 147 148 // Write-only registers 149 case OFF_QUEUE_NOTIFY: 150 case OFF_INTERRUPT_ACK: 151 warn("Guest is trying to read to write-only register 0x%\n", 152 offset); 153 return 0; 154 155 default: 156 panic("Unhandled read offset (0x%x)\n", offset); 157 } 158} 159 160Tick 161MmioVirtIO::write(PacketPtr pkt) 162{ 163 const Addr offset = pkt->getAddr() - pioAddr; 164 const unsigned size(pkt->getSize()); 165 166 DPRINTF(VIOIface, "Writing %u bytes @ 0x%x:\n", size, offset); 167 168 // Forward device configuration writes to the device VirtIO model 169 if (offset >= OFF_CONFIG) { 170 vio.writeConfig(pkt, offset - OFF_CONFIG); 171 return 0; 172 } 173 174 panic_if(size != 4, "Unexpected write size @ 0x%x: %u\n", offset, size); 175 DPRINTF(VIOIface, " value: 0x%x\n", pkt->get<uint32_t>()); 176 pkt->makeResponse(); 177 write(offset, pkt->get<uint32_t>()); 178 return 0; 179} 180 181void 182MmioVirtIO::write(Addr offset, uint32_t value) 183{ 184 switch(offset) { 185 case OFF_HOST_FEATURES_SELECT: 186 hostFeaturesSelect = value; 187 return; 188 189 case OFF_GUEST_FEATURES: 190 if (guestFeaturesSelect == 0) { 191 vio.setGuestFeatures(value); 192 } else if (value != 0) { 193 warn("Setting unimplemented guest features register %u: %u\n", 194 guestFeaturesSelect, value); 195 } 196 return; 197 198 case OFF_GUEST_FEATURES_SELECT: 199 guestFeaturesSelect = value; 200 return; 201 202 case OFF_GUEST_PAGE_SIZE: 203 // TODO: We only support 4096 byte pages at the moment 204 panic_if(value != VirtQueue::ALIGN_SIZE, 205 "Unhandled VirtIO page size: %u", value); 206 pageSize = value; 207 return; 208 209 case OFF_QUEUE_SELECT: 210 vio.setQueueSelect(value); 211 return; 212 213 case OFF_QUEUE_NUM: 214 // TODO: We don't support queue resizing, so ignore this for now. 215 warn_once("Ignoring queue resize hint. Requested size: %u\n", value); 216 return; 217 218 case OFF_QUEUE_ALIGN: 219 // TODO: We currently only support the hard-coded 4k alignment used 220 // in legacy VirtIO. 221 panic_if(value != VirtQueue::ALIGN_SIZE, 222 "Unhandled VirtIO alignment size: %u", value); 223 return; 224 225 case OFF_QUEUE_PFN: 226 vio.setQueueAddress(value); 227 return; 228 229 case OFF_QUEUE_NOTIFY: 230 vio.onNotify(value); 231 return; 232 233 case OFF_INTERRUPT_ACK: 234 setInterrupts(interruptStatus & (~value)); 235 return; 236 237 case OFF_STATUS: 238 panic_if(value > 0xff, "Unexpected status: 0x%x\n", value); 239 vio.setDeviceStatus(value); 240 return; 241 242 /* Read-only registers */ 243 case OFF_MAGIC: 244 case OFF_VERSION: 245 case OFF_DEVICE_ID: 246 case OFF_VENDOR_ID: 247 case OFF_HOST_FEATURES: 248 case OFF_QUEUE_NUM_MAX: 249 case OFF_INTERRUPT_STATUS: 250 warn("Guest is trying to write to read-only register 0x%\n", 251 offset); 252 return; 253 254 default: 255 panic("Unhandled read offset (0x%x)\n", offset); 256 } 257} 258 259void 260MmioVirtIO::kick() 261{ 262 DPRINTF(VIOIface, "kick(): Sending interrupt...\n"); 263 setInterrupts(interruptStatus | INT_USED_RING); 264} 265 266void 267MmioVirtIO::setInterrupts(uint32_t value) 268{ 269 const uint32_t old_ints = interruptStatus; 270 interruptStatus = value; 271 272 if (!old_ints && interruptStatus) { 273 interrupt->raise(); 274 } else if (old_ints && !interruptStatus) { 275 interrupt->clear(); 276 } 277} 278 279 280MmioVirtIO * 281MmioVirtIOParams::create() 282{ 283 return new MmioVirtIO(this); 284} 285