vio_mmio.cc revision 12740
15217Ssaidi@eecs.umich.edu/* 29428SAndreas.Sandberg@ARM.com * Copyright (c) 2016-2018 ARM Limited 39920Syasuko.eckert@amd.com * All rights reserved 49428SAndreas.Sandberg@ARM.com * 59428SAndreas.Sandberg@ARM.com * The license below extends only to copyright in the software and shall 69428SAndreas.Sandberg@ARM.com * not be construed as granting a license to any other intellectual 79428SAndreas.Sandberg@ARM.com * property including but not limited to intellectual property relating 89428SAndreas.Sandberg@ARM.com * to a hardware implementation of the functionality of the software 99428SAndreas.Sandberg@ARM.com * licensed hereunder. You may use the software subject to the license 109428SAndreas.Sandberg@ARM.com * terms below provided that you ensure that this notice is replicated 119428SAndreas.Sandberg@ARM.com * unmodified and in its entirety in all distributions of the software, 129428SAndreas.Sandberg@ARM.com * modified or unmodified, in source code or in binary form. 139428SAndreas.Sandberg@ARM.com * 149428SAndreas.Sandberg@ARM.com * 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 335217Ssaidi@eecs.umich.edu * 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" 466658Snate@binkert.org 479441SAndreas.Sandberg@ARM.comMmioVirtIO::MmioVirtIO(const MmioVirtIOParams *params) 489441SAndreas.Sandberg@ARM.com : BasicPioDevice(params, params->pio_size), 495217Ssaidi@eecs.umich.edu hostFeaturesSelect(0), guestFeaturesSelect(0), pageSize(0), 508232Snate@binkert.org interruptStatus(0), 519441SAndreas.Sandberg@ARM.com callbackKick(this), vio(*params->vio), interrupt(params->interrupt) 525217Ssaidi@eecs.umich.edu{ 535217Ssaidi@eecs.umich.edu fatal_if(!interrupt, "No MMIO VirtIO interrupt specified\n"); 545217Ssaidi@eecs.umich.edu 555217Ssaidi@eecs.umich.edu vio.registerKickCallback(&callbackKick); 565217Ssaidi@eecs.umich.edu} 575217Ssaidi@eecs.umich.edu 585217Ssaidi@eecs.umich.eduMmioVirtIO::~MmioVirtIO() 595217Ssaidi@eecs.umich.edu{ 605217Ssaidi@eecs.umich.edu} 615217Ssaidi@eecs.umich.edu 625217Ssaidi@eecs.umich.eduTick 635217Ssaidi@eecs.umich.eduMmioVirtIO::read(PacketPtr pkt) 645217Ssaidi@eecs.umich.edu{ 655217Ssaidi@eecs.umich.edu const Addr offset = pkt->getAddr() - pioAddr; 665217Ssaidi@eecs.umich.edu const unsigned size(pkt->getSize()); 675217Ssaidi@eecs.umich.edu 685217Ssaidi@eecs.umich.edu DPRINTF(VIOIface, "Reading %u bytes @ 0x%x:\n", size, offset); 695217Ssaidi@eecs.umich.edu 705217Ssaidi@eecs.umich.edu // Forward device configuration writes to the device VirtIO model 715217Ssaidi@eecs.umich.edu if (offset >= OFF_CONFIG) { 725217Ssaidi@eecs.umich.edu vio.readConfig(pkt, offset - OFF_CONFIG); 735217Ssaidi@eecs.umich.edu return 0; 745217Ssaidi@eecs.umich.edu } 755217Ssaidi@eecs.umich.edu 765217Ssaidi@eecs.umich.edu panic_if(size != 4, "Unexpected read size: %u\n", size); 775217Ssaidi@eecs.umich.edu 785217Ssaidi@eecs.umich.edu const uint32_t value = read(offset); 795217Ssaidi@eecs.umich.edu DPRINTF(VIOIface, " value: 0x%x\n", value); 805217Ssaidi@eecs.umich.edu pkt->makeResponse(); 815217Ssaidi@eecs.umich.edu pkt->set<uint32_t>(value); 825217Ssaidi@eecs.umich.edu 839920Syasuko.eckert@amd.com return 0; 849920Syasuko.eckert@amd.com} 859920Syasuko.eckert@amd.com 869920Syasuko.eckert@amd.comuint32_t 879920Syasuko.eckert@amd.comMmioVirtIO::read(Addr offset) 889920Syasuko.eckert@amd.com{ 899920Syasuko.eckert@amd.com switch(offset) { 909920Syasuko.eckert@amd.com case OFF_MAGIC: 917720Sgblack@eecs.umich.edu return MAGIC; 927720Sgblack@eecs.umich.edu 935712Shsul@eecs.umich.edu case OFF_VERSION: 945712Shsul@eecs.umich.edu return VERSION; 955217Ssaidi@eecs.umich.edu 965217Ssaidi@eecs.umich.edu case OFF_DEVICE_ID: 975714Shsul@eecs.umich.edu return vio.deviceId; 985714Shsul@eecs.umich.edu 995714Shsul@eecs.umich.edu case OFF_VENDOR_ID: 1005714Shsul@eecs.umich.edu return VENDOR_ID; 1015714Shsul@eecs.umich.edu 1025714Shsul@eecs.umich.edu case OFF_HOST_FEATURES: 1035714Shsul@eecs.umich.edu // We only implement 32 bits of this register 1045217Ssaidi@eecs.umich.edu if (hostFeaturesSelect == 0) 1059428SAndreas.Sandberg@ARM.com return vio.deviceFeatures; 1069428SAndreas.Sandberg@ARM.com else 10710905Sandreas.sandberg@arm.com return 0; 1089428SAndreas.Sandberg@ARM.com 1099428SAndreas.Sandberg@ARM.com case OFF_HOST_FEATURES_SELECT: 1109428SAndreas.Sandberg@ARM.com return hostFeaturesSelect; 1119428SAndreas.Sandberg@ARM.com 1129428SAndreas.Sandberg@ARM.com case OFF_GUEST_FEATURES: 1139428SAndreas.Sandberg@ARM.com // We only implement 32 bits of this register 1149428SAndreas.Sandberg@ARM.com if (guestFeaturesSelect == 0) 1159428SAndreas.Sandberg@ARM.com return vio.getGuestFeatures(); 11610905Sandreas.sandberg@arm.com else 1179428SAndreas.Sandberg@ARM.com return 0; 1189428SAndreas.Sandberg@ARM.com 1199428SAndreas.Sandberg@ARM.com case OFF_GUEST_FEATURES_SELECT: 1209428SAndreas.Sandberg@ARM.com return hostFeaturesSelect; 1219428SAndreas.Sandberg@ARM.com 1229428SAndreas.Sandberg@ARM.com case OFF_GUEST_PAGE_SIZE: 1239920Syasuko.eckert@amd.com return pageSize; 1249920Syasuko.eckert@amd.com 1259920Syasuko.eckert@amd.com case OFF_QUEUE_SELECT: 1269920Syasuko.eckert@amd.com return vio.getQueueSelect(); 1279920Syasuko.eckert@amd.com 1289920Syasuko.eckert@amd.com case OFF_QUEUE_NUM_MAX: 1299920Syasuko.eckert@amd.com return vio.getQueueSize(); 13010905Sandreas.sandberg@arm.com 1319428SAndreas.Sandberg@ARM.com case OFF_QUEUE_NUM: 1329428SAndreas.Sandberg@ARM.com // TODO: We don't support queue resizing, so ignore this for now. 1339428SAndreas.Sandberg@ARM.com return vio.getQueueSize(); 1349428SAndreas.Sandberg@ARM.com 1359428SAndreas.Sandberg@ARM.com case OFF_QUEUE_ALIGN: 13610905Sandreas.sandberg@arm.com // TODO: Implement this once we support other alignment sizes 1379428SAndreas.Sandberg@ARM.com return VirtQueue::ALIGN_SIZE; 1389428SAndreas.Sandberg@ARM.com 1399428SAndreas.Sandberg@ARM.com case OFF_QUEUE_PFN: 1409428SAndreas.Sandberg@ARM.com return vio.getQueueAddress(); 1419428SAndreas.Sandberg@ARM.com 1429428SAndreas.Sandberg@ARM.com case OFF_INTERRUPT_STATUS: 14310905Sandreas.sandberg@arm.com return interruptStatus; 1449428SAndreas.Sandberg@ARM.com 1459428SAndreas.Sandberg@ARM.com case OFF_STATUS: 1469428SAndreas.Sandberg@ARM.com return vio.getDeviceStatus(); 1479428SAndreas.Sandberg@ARM.com 1489428SAndreas.Sandberg@ARM.com // Write-only registers 1499428SAndreas.Sandberg@ARM.com case OFF_QUEUE_NOTIFY: 1509428SAndreas.Sandberg@ARM.com case OFF_INTERRUPT_ACK: 1519428SAndreas.Sandberg@ARM.com warn("Guest is trying to read to write-only register 0x%\n", 1529920Syasuko.eckert@amd.com offset); 1539920Syasuko.eckert@amd.com return 0; 1549920Syasuko.eckert@amd.com 1559920Syasuko.eckert@amd.com default: 1569920Syasuko.eckert@amd.com panic("Unhandled read offset (0x%x)\n", offset); 1579920Syasuko.eckert@amd.com } 1589920Syasuko.eckert@amd.com} 1599428SAndreas.Sandberg@ARM.com 16010905Sandreas.sandberg@arm.comTick 1619428SAndreas.Sandberg@ARM.comMmioVirtIO::write(PacketPtr pkt) 1629428SAndreas.Sandberg@ARM.com{ 1639428SAndreas.Sandberg@ARM.com const Addr offset = pkt->getAddr() - pioAddr; 1649428SAndreas.Sandberg@ARM.com const unsigned size(pkt->getSize()); 1659441SAndreas.Sandberg@ARM.com 1669441SAndreas.Sandberg@ARM.com DPRINTF(VIOIface, "Writing %u bytes @ 0x%x:\n", size, offset); 1679441SAndreas.Sandberg@ARM.com 1689441SAndreas.Sandberg@ARM.com // Forward device configuration writes to the device VirtIO model 1699441SAndreas.Sandberg@ARM.com if (offset >= OFF_CONFIG) { 1709441SAndreas.Sandberg@ARM.com vio.writeConfig(pkt, offset - OFF_CONFIG); 1719441SAndreas.Sandberg@ARM.com return 0; 1729441SAndreas.Sandberg@ARM.com } 1739441SAndreas.Sandberg@ARM.com 1749441SAndreas.Sandberg@ARM.com panic_if(size != 4, "Unexpected write size @ 0x%x: %u\n", offset, size); 1759441SAndreas.Sandberg@ARM.com DPRINTF(VIOIface, " value: 0x%x\n", pkt->get<uint32_t>()); 1769441SAndreas.Sandberg@ARM.com pkt->makeResponse(); 1779441SAndreas.Sandberg@ARM.com write(offset, pkt->get<uint32_t>()); 1789441SAndreas.Sandberg@ARM.com return 0; 1799441SAndreas.Sandberg@ARM.com} 1809441SAndreas.Sandberg@ARM.com 1819441SAndreas.Sandberg@ARM.comvoid 1829441SAndreas.Sandberg@ARM.comMmioVirtIO::write(Addr offset, uint32_t value) 1839441SAndreas.Sandberg@ARM.com{ 1849441SAndreas.Sandberg@ARM.com switch(offset) { 1859441SAndreas.Sandberg@ARM.com case OFF_HOST_FEATURES_SELECT: 1869441SAndreas.Sandberg@ARM.com hostFeaturesSelect = value; 1879441SAndreas.Sandberg@ARM.com return; 1889441SAndreas.Sandberg@ARM.com 1899441SAndreas.Sandberg@ARM.com case OFF_GUEST_FEATURES: 1909441SAndreas.Sandberg@ARM.com if (guestFeaturesSelect == 0) { 1919441SAndreas.Sandberg@ARM.com vio.setGuestFeatures(value); 1929441SAndreas.Sandberg@ARM.com } else if (value != 0) { 1939441SAndreas.Sandberg@ARM.com warn("Setting unimplemented guest features register %u: %u\n", 1949441SAndreas.Sandberg@ARM.com guestFeaturesSelect, value); 1959441SAndreas.Sandberg@ARM.com } 1969441SAndreas.Sandberg@ARM.com return; 1979441SAndreas.Sandberg@ARM.com 1989441SAndreas.Sandberg@ARM.com 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