pci.cc revision 11930
13101Sstever@eecs.umich.edu/* 23101Sstever@eecs.umich.edu * Copyright (c) 2014 ARM Limited 33101Sstever@eecs.umich.edu * All rights reserved 43101Sstever@eecs.umich.edu * 53101Sstever@eecs.umich.edu * The license below extends only to copyright in the software and shall 63101Sstever@eecs.umich.edu * not be construed as granting a license to any other intellectual 73101Sstever@eecs.umich.edu * property including but not limited to intellectual property relating 83101Sstever@eecs.umich.edu * to a hardware implementation of the functionality of the software 93101Sstever@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 103101Sstever@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 113101Sstever@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 123101Sstever@eecs.umich.edu * modified or unmodified, in source code or in binary form. 133101Sstever@eecs.umich.edu * 143101Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 153101Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are 163101Sstever@eecs.umich.edu * met: redistributions of source code must retain the above copyright 173101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 183101Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 193101Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 203101Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution; 213101Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its 223101Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from 233101Sstever@eecs.umich.edu * this software without specific prior written permission. 243101Sstever@eecs.umich.edu * 253101Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 263101Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 273101Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 283101Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 293101Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 303101Sstever@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 313101Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 323101Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 333101Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 343101Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 353101Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 363101Sstever@eecs.umich.edu * 373101Sstever@eecs.umich.edu * Authors: Andreas Sandberg 383101Sstever@eecs.umich.edu */ 393101Sstever@eecs.umich.edu 403101Sstever@eecs.umich.edu#include "dev/virtio/pci.hh" 413101Sstever@eecs.umich.edu 423101Sstever@eecs.umich.edu#include "debug/VIOIface.hh" 433101Sstever@eecs.umich.edu#include "mem/packet_access.hh" 443101Sstever@eecs.umich.edu#include "params/PciVirtIO.hh" 453101Sstever@eecs.umich.edu 463101Sstever@eecs.umich.eduPciVirtIO::PciVirtIO(const Params *params) 473885Sbinkertn@umich.edu : PciDevice(params), queueNotify(0), interruptDeliveryPending(false), 483885Sbinkertn@umich.edu vio(*params->vio), callbackKick(this) 494762Snate@binkert.org{ 503885Sbinkertn@umich.edu // Override the subsystem ID with the device ID from VirtIO 513885Sbinkertn@umich.edu config.subsystemID = htole(vio.deviceId); 527528Ssteve.reinhardt@amd.com BARSize[0] = BAR0_SIZE_BASE + vio.configSize; 533885Sbinkertn@umich.edu 544380Sbinkertn@umich.edu vio.registerKickCallback(&callbackKick); 554167Sbinkertn@umich.edu} 563102Sstever@eecs.umich.edu 573101Sstever@eecs.umich.eduPciVirtIO::~PciVirtIO() 584762Snate@binkert.org{ 594762Snate@binkert.org} 604762Snate@binkert.org 614762Snate@binkert.orgTick 624762Snate@binkert.orgPciVirtIO::read(PacketPtr pkt) 634762Snate@binkert.org{ 644762Snate@binkert.org const unsigned M5_VAR_USED size(pkt->getSize()); 654762Snate@binkert.org int bar; 664762Snate@binkert.org Addr offset; 675033Smilesck@eecs.umich.edu if (!getBAR(pkt->getAddr(), bar, offset)) 685033Smilesck@eecs.umich.edu panic("Invalid PCI memory access to unmapped memory.\n"); 695033Smilesck@eecs.umich.edu assert(bar == 0); 705033Smilesck@eecs.umich.edu 715033Smilesck@eecs.umich.edu DPRINTF(VIOIface, "Reading offset 0x%x [len: %i]\n", offset, size); 725033Smilesck@eecs.umich.edu 735033Smilesck@eecs.umich.edu // Forward device configuration writes to the device VirtIO model 745033Smilesck@eecs.umich.edu if (offset >= OFF_VIO_DEVICE) { 755033Smilesck@eecs.umich.edu vio.readConfig(pkt, offset - OFF_VIO_DEVICE); 765033Smilesck@eecs.umich.edu return 0; 773101Sstever@eecs.umich.edu } 783101Sstever@eecs.umich.edu 793101Sstever@eecs.umich.edu pkt->makeResponse(); 805033Smilesck@eecs.umich.edu 813101Sstever@eecs.umich.edu switch(offset) { 823101Sstever@eecs.umich.edu case OFF_DEVICE_FEATURES: 833101Sstever@eecs.umich.edu DPRINTF(VIOIface, " DEVICE_FEATURES request\n"); 843101Sstever@eecs.umich.edu assert(size == sizeof(uint32_t)); 853101Sstever@eecs.umich.edu pkt->set<uint32_t>(vio.deviceFeatures); 863101Sstever@eecs.umich.edu break; 873101Sstever@eecs.umich.edu 883101Sstever@eecs.umich.edu case OFF_GUEST_FEATURES: 893101Sstever@eecs.umich.edu DPRINTF(VIOIface, " GUEST_FEATURES request\n"); 903101Sstever@eecs.umich.edu assert(size == sizeof(uint32_t)); 913101Sstever@eecs.umich.edu pkt->set<uint32_t>(vio.getGuestFeatures()); 923101Sstever@eecs.umich.edu break; 933101Sstever@eecs.umich.edu 943101Sstever@eecs.umich.edu case OFF_QUEUE_ADDRESS: 953101Sstever@eecs.umich.edu DPRINTF(VIOIface, " QUEUE_ADDRESS request\n"); 963101Sstever@eecs.umich.edu assert(size == sizeof(uint32_t)); 976656Snate@binkert.org pkt->set<uint32_t>(vio.getQueueAddress()); 986656Snate@binkert.org break; 993101Sstever@eecs.umich.edu 1003101Sstever@eecs.umich.edu case OFF_QUEUE_SIZE: 1013101Sstever@eecs.umich.edu DPRINTF(VIOIface, " QUEUE_SIZE request\n"); 1023101Sstever@eecs.umich.edu assert(size == sizeof(uint16_t)); 1033101Sstever@eecs.umich.edu pkt->set<uint16_t>(vio.getQueueSize()); 1043101Sstever@eecs.umich.edu break; 1053101Sstever@eecs.umich.edu 1063101Sstever@eecs.umich.edu case OFF_QUEUE_SELECT: 1073101Sstever@eecs.umich.edu DPRINTF(VIOIface, " QUEUE_SELECT\n"); 1083101Sstever@eecs.umich.edu assert(size == sizeof(uint16_t)); 1093101Sstever@eecs.umich.edu pkt->set<uint16_t>(vio.getQueueSelect()); 1103101Sstever@eecs.umich.edu break; 1113101Sstever@eecs.umich.edu 1123101Sstever@eecs.umich.edu case OFF_QUEUE_NOTIFY: 1133101Sstever@eecs.umich.edu DPRINTF(VIOIface, " QUEUE_NOTIFY request\n"); 1143101Sstever@eecs.umich.edu assert(size == sizeof(uint16_t)); 1153101Sstever@eecs.umich.edu pkt->set<uint16_t>(queueNotify); 1163101Sstever@eecs.umich.edu break; 1173101Sstever@eecs.umich.edu 1183101Sstever@eecs.umich.edu case OFF_DEVICE_STATUS: 1193101Sstever@eecs.umich.edu DPRINTF(VIOIface, " DEVICE_STATUS request\n"); 1203101Sstever@eecs.umich.edu assert(size == sizeof(uint8_t)); 1213101Sstever@eecs.umich.edu pkt->set<uint8_t>(vio.getDeviceStatus()); 1223101Sstever@eecs.umich.edu break; 1233101Sstever@eecs.umich.edu 1243101Sstever@eecs.umich.edu case OFF_ISR_STATUS: { 1253101Sstever@eecs.umich.edu DPRINTF(VIOIface, " ISR_STATUS\n"); 1263101Sstever@eecs.umich.edu assert(size == sizeof(uint8_t)); 1273101Sstever@eecs.umich.edu const uint8_t isr_status(interruptDeliveryPending ? 1 : 0); 1283101Sstever@eecs.umich.edu if (interruptDeliveryPending) { 1293101Sstever@eecs.umich.edu interruptDeliveryPending = false; 1303101Sstever@eecs.umich.edu intrClear(); 1313101Sstever@eecs.umich.edu } 1325033Smilesck@eecs.umich.edu pkt->set<uint8_t>(isr_status); 1336656Snate@binkert.org } break; 1345033Smilesck@eecs.umich.edu 1355033Smilesck@eecs.umich.edu default: 1365033Smilesck@eecs.umich.edu panic("Unhandled read offset (0x%x)\n", offset); 1373101Sstever@eecs.umich.edu } 1383101Sstever@eecs.umich.edu 1393101Sstever@eecs.umich.edu return 0; 1403101Sstever@eecs.umich.edu} 1413101Sstever@eecs.umich.edu 1423101Sstever@eecs.umich.eduTick 1433101Sstever@eecs.umich.eduPciVirtIO::write(PacketPtr pkt) 1443101Sstever@eecs.umich.edu{ 1453101Sstever@eecs.umich.edu const unsigned M5_VAR_USED size(pkt->getSize()); 1463101Sstever@eecs.umich.edu int bar; 1473101Sstever@eecs.umich.edu Addr offset; 1483101Sstever@eecs.umich.edu if (!getBAR(pkt->getAddr(), bar, offset)) 1493101Sstever@eecs.umich.edu panic("Invalid PCI memory access to unmapped memory.\n"); 1503102Sstever@eecs.umich.edu assert(bar == 0); 1513101Sstever@eecs.umich.edu 1523101Sstever@eecs.umich.edu DPRINTF(VIOIface, "Writing offset 0x%x [len: %i]\n", offset, size); 1533101Sstever@eecs.umich.edu 1543101Sstever@eecs.umich.edu // Forward device configuration writes to the device VirtIO model 1553101Sstever@eecs.umich.edu if (offset >= OFF_VIO_DEVICE) { 1563101Sstever@eecs.umich.edu vio.writeConfig(pkt, offset - OFF_VIO_DEVICE); 1573101Sstever@eecs.umich.edu return 0; 1583101Sstever@eecs.umich.edu } 1593101Sstever@eecs.umich.edu 1603101Sstever@eecs.umich.edu pkt->makeResponse(); 1613101Sstever@eecs.umich.edu 1623101Sstever@eecs.umich.edu switch(offset) { 1633101Sstever@eecs.umich.edu case OFF_DEVICE_FEATURES: 1643101Sstever@eecs.umich.edu warn("Guest tried to write device features."); 1653101Sstever@eecs.umich.edu break; 1663101Sstever@eecs.umich.edu 1673101Sstever@eecs.umich.edu case OFF_GUEST_FEATURES: 1685033Smilesck@eecs.umich.edu DPRINTF(VIOIface, " WRITE GUEST_FEATURES request\n"); 1695475Snate@binkert.org assert(size == sizeof(uint32_t)); 1705475Snate@binkert.org vio.setGuestFeatures(pkt->get<uint32_t>()); 1715475Snate@binkert.org break; 1725475Snate@binkert.org 1733101Sstever@eecs.umich.edu case OFF_QUEUE_ADDRESS: 1743101Sstever@eecs.umich.edu DPRINTF(VIOIface, " WRITE QUEUE_ADDRESS\n"); 1753101Sstever@eecs.umich.edu assert(size == sizeof(uint32_t)); 1764762Snate@binkert.org vio.setQueueAddress(pkt->get<uint32_t>()); 1774762Snate@binkert.org break; 1784762Snate@binkert.org 1793101Sstever@eecs.umich.edu case OFF_QUEUE_SIZE: 1803101Sstever@eecs.umich.edu panic("Guest tried to write queue size."); 1813101Sstever@eecs.umich.edu break; 1827528Ssteve.reinhardt@amd.com 1837528Ssteve.reinhardt@amd.com case OFF_QUEUE_SELECT: 1847528Ssteve.reinhardt@amd.com DPRINTF(VIOIface, " WRITE QUEUE_SELECT\n"); 1857528Ssteve.reinhardt@amd.com assert(size == sizeof(uint16_t)); 1867528Ssteve.reinhardt@amd.com vio.setQueueSelect(pkt->get<uint16_t>()); 1877528Ssteve.reinhardt@amd.com break; 1883101Sstever@eecs.umich.edu 1897528Ssteve.reinhardt@amd.com case OFF_QUEUE_NOTIFY: 1907528Ssteve.reinhardt@amd.com DPRINTF(VIOIface, " WRITE QUEUE_NOTIFY\n"); 1917528Ssteve.reinhardt@amd.com assert(size == sizeof(uint16_t)); 1927528Ssteve.reinhardt@amd.com queueNotify = pkt->get<uint16_t>(); 1937528Ssteve.reinhardt@amd.com vio.onNotify(queueNotify); 1947528Ssteve.reinhardt@amd.com break; 1957528Ssteve.reinhardt@amd.com 1967528Ssteve.reinhardt@amd.com case OFF_DEVICE_STATUS: { 1977528Ssteve.reinhardt@amd.com assert(size == sizeof(uint8_t)); 1987528Ssteve.reinhardt@amd.com uint8_t status(pkt->get<uint8_t>()); 1997528Ssteve.reinhardt@amd.com DPRINTF(VIOIface, "VirtIO set status: 0x%x\n", status); 2007528Ssteve.reinhardt@amd.com vio.setDeviceStatus(status); 2017528Ssteve.reinhardt@amd.com } break; 2027528Ssteve.reinhardt@amd.com 2037528Ssteve.reinhardt@amd.com case OFF_ISR_STATUS: 2047528Ssteve.reinhardt@amd.com warn("Guest tried to write ISR status."); 2057528Ssteve.reinhardt@amd.com break; 2067528Ssteve.reinhardt@amd.com 2077528Ssteve.reinhardt@amd.com default: 2087528Ssteve.reinhardt@amd.com panic("Unhandled read offset (0x%x)\n", offset); 2097528Ssteve.reinhardt@amd.com } 2107528Ssteve.reinhardt@amd.com 2117528Ssteve.reinhardt@amd.com return 0; 2127528Ssteve.reinhardt@amd.com} 2137528Ssteve.reinhardt@amd.com 2147528Ssteve.reinhardt@amd.comvoid 2157528Ssteve.reinhardt@amd.comPciVirtIO::kick() 2167528Ssteve.reinhardt@amd.com{ 2177528Ssteve.reinhardt@amd.com DPRINTF(VIOIface, "kick(): Sending interrupt...\n"); 2183101Sstever@eecs.umich.edu interruptDeliveryPending = true; 2193101Sstever@eecs.umich.edu intrPost(); 2206656Snate@binkert.org} 2216656Snate@binkert.org 2223101Sstever@eecs.umich.eduPciVirtIO * 2233101Sstever@eecs.umich.eduPciVirtIOParams::create() 2243101Sstever@eecs.umich.edu{ 2253101Sstever@eecs.umich.edu return new PciVirtIO(this); 2263101Sstever@eecs.umich.edu} 2273101Sstever@eecs.umich.edu