vio_mmio.cc revision 12974
15217Ssaidi@eecs.umich.edu/* 25217Ssaidi@eecs.umich.edu * Copyright (c) 2016-2018 ARM Limited 35217Ssaidi@eecs.umich.edu * All rights reserved 45217Ssaidi@eecs.umich.edu * 55217Ssaidi@eecs.umich.edu * The license below extends only to copyright in the software and shall 65217Ssaidi@eecs.umich.edu * not be construed as granting a license to any other intellectual 75217Ssaidi@eecs.umich.edu * property including but not limited to intellectual property relating 85217Ssaidi@eecs.umich.edu * to a hardware implementation of the functionality of the software 95217Ssaidi@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 105217Ssaidi@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 115217Ssaidi@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 125217Ssaidi@eecs.umich.edu * modified or unmodified, in source code or in binary form. 135217Ssaidi@eecs.umich.edu * 145217Ssaidi@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 155217Ssaidi@eecs.umich.edu * modification, are permitted provided that the following conditions are 165217Ssaidi@eecs.umich.edu * met: redistributions of source code must retain the above copyright 175217Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 185217Ssaidi@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 195217Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 205217Ssaidi@eecs.umich.edu * documentation and/or other materials provided with the distribution; 215217Ssaidi@eecs.umich.edu * neither the name of the copyright holders nor the names of its 225217Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from 235217Ssaidi@eecs.umich.edu * this software without specific prior written permission. 245217Ssaidi@eecs.umich.edu * 255217Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 265217Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 275217Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 285217Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 295217Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 305217Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 315217Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 325217Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 336658Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 345217Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 355217Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 365217Ssaidi@eecs.umich.edu * 375217Ssaidi@eecs.umich.edu * Authors: Andreas Sandberg 385217Ssaidi@eecs.umich.edu */ 395217Ssaidi@eecs.umich.edu 405217Ssaidi@eecs.umich.edu#include "dev/arm/vio_mmio.hh" 415217Ssaidi@eecs.umich.edu 425217Ssaidi@eecs.umich.edu#include "debug/VIOIface.hh" 435217Ssaidi@eecs.umich.edu#include "dev/arm/base_gic.hh" 445217Ssaidi@eecs.umich.edu#include "mem/packet_access.hh" 455217Ssaidi@eecs.umich.edu#include "params/MmioVirtIO.hh" 465217Ssaidi@eecs.umich.edu 475217Ssaidi@eecs.umich.eduMmioVirtIO::MmioVirtIO(const MmioVirtIOParams *params) 485217Ssaidi@eecs.umich.edu : BasicPioDevice(params, params->pio_size), 495217Ssaidi@eecs.umich.edu hostFeaturesSelect(0), guestFeaturesSelect(0), pageSize(0), 505217Ssaidi@eecs.umich.edu interruptStatus(0), 515217Ssaidi@eecs.umich.edu callbackKick(this), vio(*params->vio), 525217Ssaidi@eecs.umich.edu interrupt(params->interrupt->get()) 535217Ssaidi@eecs.umich.edu{ 545217Ssaidi@eecs.umich.edu fatal_if(!interrupt, "No MMIO VirtIO interrupt specified\n"); 555217Ssaidi@eecs.umich.edu 565217Ssaidi@eecs.umich.edu vio.registerKickCallback(&callbackKick); 575217Ssaidi@eecs.umich.edu} 585217Ssaidi@eecs.umich.edu 595217Ssaidi@eecs.umich.eduMmioVirtIO::~MmioVirtIO() 605217Ssaidi@eecs.umich.edu{ 615217Ssaidi@eecs.umich.edu} 625217Ssaidi@eecs.umich.edu 635217Ssaidi@eecs.umich.eduTick 645217Ssaidi@eecs.umich.eduMmioVirtIO::read(PacketPtr pkt) 655217Ssaidi@eecs.umich.edu{ 665217Ssaidi@eecs.umich.edu const Addr offset = pkt->getAddr() - pioAddr; 675217Ssaidi@eecs.umich.edu const unsigned size(pkt->getSize()); 687720Sgblack@eecs.umich.edu 697720Sgblack@eecs.umich.edu DPRINTF(VIOIface, "Reading %u bytes @ 0x%x:\n", size, offset); 705712Shsul@eecs.umich.edu 715712Shsul@eecs.umich.edu // Forward device configuration writes to the device VirtIO model 725217Ssaidi@eecs.umich.edu if (offset >= OFF_CONFIG) { 735217Ssaidi@eecs.umich.edu vio.readConfig(pkt, offset - OFF_CONFIG); 745714Shsul@eecs.umich.edu return 0; 755714Shsul@eecs.umich.edu } 765714Shsul@eecs.umich.edu 775714Shsul@eecs.umich.edu panic_if(size != 4, "Unexpected read size: %u\n", size); 785714Shsul@eecs.umich.edu 795714Shsul@eecs.umich.edu const uint32_t value = read(offset); 805714Shsul@eecs.umich.edu DPRINTF(VIOIface, " value: 0x%x\n", value); 815217Ssaidi@eecs.umich.edu pkt->makeResponse(); 82 pkt->set<uint32_t>(value); 83 84 return 0; 85} 86 87uint32_t 88MmioVirtIO::read(Addr offset) 89{ 90 switch(offset) { 91 case OFF_MAGIC: 92 return MAGIC; 93 94 case OFF_VERSION: 95 return VERSION; 96 97 case OFF_DEVICE_ID: 98 return vio.deviceId; 99 100 case OFF_VENDOR_ID: 101 return VENDOR_ID; 102 103 case OFF_HOST_FEATURES: 104 // We only implement 32 bits of this register 105 if (hostFeaturesSelect == 0) 106 return vio.deviceFeatures; 107 else 108 return 0; 109 110 case OFF_HOST_FEATURES_SELECT: 111 return hostFeaturesSelect; 112 113 case OFF_GUEST_FEATURES: 114 // We only implement 32 bits of this register 115 if (guestFeaturesSelect == 0) 116 return vio.getGuestFeatures(); 117 else 118 return 0; 119 120 case OFF_GUEST_FEATURES_SELECT: 121 return hostFeaturesSelect; 122 123 case OFF_GUEST_PAGE_SIZE: 124 return pageSize; 125 126 case OFF_QUEUE_SELECT: 127 return vio.getQueueSelect(); 128 129 case OFF_QUEUE_NUM_MAX: 130 return vio.getQueueSize(); 131 132 case OFF_QUEUE_NUM: 133 // TODO: We don't support queue resizing, so ignore this for now. 134 return vio.getQueueSize(); 135 136 case OFF_QUEUE_ALIGN: 137 // TODO: Implement this once we support other alignment sizes 138 return VirtQueue::ALIGN_SIZE; 139 140 case OFF_QUEUE_PFN: 141 return vio.getQueueAddress(); 142 143 case OFF_INTERRUPT_STATUS: 144 return interruptStatus; 145 146 case OFF_STATUS: 147 return vio.getDeviceStatus(); 148 149 // Write-only registers 150 case OFF_QUEUE_NOTIFY: 151 case OFF_INTERRUPT_ACK: 152 warn("Guest is trying to read to write-only register 0x%\n", 153 offset); 154 return 0; 155 156 default: 157 panic("Unhandled read offset (0x%x)\n", offset); 158 } 159} 160 161Tick 162MmioVirtIO::write(PacketPtr pkt) 163{ 164 const Addr offset = pkt->getAddr() - pioAddr; 165 const unsigned size(pkt->getSize()); 166 167 DPRINTF(VIOIface, "Writing %u bytes @ 0x%x:\n", size, offset); 168 169 // Forward device configuration writes to the device VirtIO model 170 if (offset >= OFF_CONFIG) { 171 vio.writeConfig(pkt, offset - OFF_CONFIG); 172 return 0; 173 } 174 175 panic_if(size != 4, "Unexpected write size @ 0x%x: %u\n", offset, size); 176 DPRINTF(VIOIface, " value: 0x%x\n", pkt->get<uint32_t>()); 177 pkt->makeResponse(); 178 write(offset, pkt->get<uint32_t>()); 179 return 0; 180} 181 182void 183MmioVirtIO::write(Addr offset, uint32_t value) 184{ 185 switch(offset) { 186 case OFF_HOST_FEATURES_SELECT: 187 hostFeaturesSelect = value; 188 return; 189 190 case OFF_GUEST_FEATURES: 191 if (guestFeaturesSelect == 0) { 192 vio.setGuestFeatures(value); 193 } else if (value != 0) { 194 warn("Setting unimplemented guest features register %u: %u\n", 195 guestFeaturesSelect, value); 196 } 197 return; 198 199 case OFF_GUEST_FEATURES_SELECT: 200 guestFeaturesSelect = value; 201 return; 202 203 case OFF_GUEST_PAGE_SIZE: 204 // TODO: We only support 4096 byte pages at the moment 205 panic_if(value != VirtQueue::ALIGN_SIZE, 206 "Unhandled VirtIO page size: %u", value); 207 pageSize = value; 208 return; 209 210 case OFF_QUEUE_SELECT: 211 vio.setQueueSelect(value); 212 return; 213 214 case OFF_QUEUE_NUM: 215 // TODO: We don't support queue resizing, so ignore this for now. 216 warn_once("Ignoring queue resize hint. Requested size: %u\n", value); 217 return; 218 219 case OFF_QUEUE_ALIGN: 220 // TODO: We currently only support the hard-coded 4k alignment used 221 // in legacy VirtIO. 222 panic_if(value != VirtQueue::ALIGN_SIZE, 223 "Unhandled VirtIO alignment size: %u", value); 224 return; 225 226 case OFF_QUEUE_PFN: 227 vio.setQueueAddress(value); 228 return; 229 230 case OFF_QUEUE_NOTIFY: 231 vio.onNotify(value); 232 return; 233 234 case OFF_INTERRUPT_ACK: 235 setInterrupts(interruptStatus & (~value)); 236 return; 237 238 case OFF_STATUS: 239 panic_if(value > 0xff, "Unexpected status: 0x%x\n", value); 240 vio.setDeviceStatus(value); 241 return; 242 243 /* Read-only registers */ 244 case OFF_MAGIC: 245 case OFF_VERSION: 246 case OFF_DEVICE_ID: 247 case OFF_VENDOR_ID: 248 case OFF_HOST_FEATURES: 249 case OFF_QUEUE_NUM_MAX: 250 case OFF_INTERRUPT_STATUS: 251 warn("Guest is trying to write to read-only register 0x%\n", 252 offset); 253 return; 254 255 default: 256 panic("Unhandled read offset (0x%x)\n", offset); 257 } 258} 259 260void 261MmioVirtIO::kick() 262{ 263 DPRINTF(VIOIface, "kick(): Sending interrupt...\n"); 264 setInterrupts(interruptStatus | INT_USED_RING); 265} 266 267void 268MmioVirtIO::setInterrupts(uint32_t value) 269{ 270 const uint32_t old_ints = interruptStatus; 271 interruptStatus = value; 272 273 if (!old_ints && interruptStatus) { 274 interrupt->raise(); 275 } else if (old_ints && !interruptStatus) { 276 interrupt->clear(); 277 } 278} 279 280 281MmioVirtIO * 282MmioVirtIOParams::create() 283{ 284 return new MmioVirtIO(this); 285} 286