pci.cc revision 11793
1955SN/A/* 2955SN/A * Copyright (c) 2014 ARM Limited 31762SN/A * All rights reserved 4955SN/A * 5955SN/A * The license below extends only to copyright in the software and shall 6955SN/A * not be construed as granting a license to any other intellectual 7955SN/A * property including but not limited to intellectual property relating 8955SN/A * to a hardware implementation of the functionality of the software 9955SN/A * licensed hereunder. You may use the software subject to the license 10955SN/A * terms below provided that you ensure that this notice is replicated 11955SN/A * unmodified and in its entirety in all distributions of the software, 12955SN/A * modified or unmodified, in source code or in binary form. 13955SN/A * 14955SN/A * Redistribution and use in source and binary forms, with or without 15955SN/A * modification, are permitted provided that the following conditions are 16955SN/A * met: redistributions of source code must retain the above copyright 17955SN/A * notice, this list of conditions and the following disclaimer; 18955SN/A * redistributions in binary form must reproduce the above copyright 19955SN/A * notice, this list of conditions and the following disclaimer in the 20955SN/A * documentation and/or other materials provided with the distribution; 21955SN/A * neither the name of the copyright holders nor the names of its 22955SN/A * contributors may be used to endorse or promote products derived from 23955SN/A * this software without specific prior written permission. 24955SN/A * 25955SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26955SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27955SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282665Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 294762Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30955SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 315522Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 324762Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 335522Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34955SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 355522Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36955SN/A * 375522Snate@binkert.org * Authors: Andreas Sandberg 384202Sbinkertn@umich.edu */ 395742Snate@binkert.org 40955SN/A#include "dev/virtio/pci.hh" 414381Sbinkertn@umich.edu 424381Sbinkertn@umich.edu#include "debug/VIOPci.hh" 43955SN/A#include "mem/packet_access.hh" 44955SN/A#include "params/PciVirtIO.hh" 45955SN/A 464202Sbinkertn@umich.eduPciVirtIO::PciVirtIO(const Params *params) 47955SN/A : PciDevice(params), queueNotify(0), interruptDeliveryPending(false), 484382Sbinkertn@umich.edu vio(*params->vio), callbackKick(this) 494382Sbinkertn@umich.edu{ 504382Sbinkertn@umich.edu // Override the subsystem ID with the device ID from VirtIO 515863Snate@binkert.org config.subsystemID = htole(vio.deviceId); 525517Snate@binkert.org BARSize[0] = BAR0_SIZE_BASE + vio.configSize; 534762Snate@binkert.org 544762Snate@binkert.org vio.registerKickCallback(&callbackKick); 554762Snate@binkert.org} 564762Snate@binkert.org 574762Snate@binkert.orgPciVirtIO::~PciVirtIO() 584762Snate@binkert.org{ 594762Snate@binkert.org} 604762Snate@binkert.org 614762Snate@binkert.orgTick 624762Snate@binkert.orgPciVirtIO::read(PacketPtr pkt) 635522Snate@binkert.org{ 645604Snate@binkert.org const unsigned M5_VAR_USED size(pkt->getSize()); 655604Snate@binkert.org int bar; 665604Snate@binkert.org Addr offset; 674762Snate@binkert.org if (!getBAR(pkt->getAddr(), bar, offset)) 684762Snate@binkert.org panic("Invalid PCI memory access to unmapped memory.\n"); 694762Snate@binkert.org assert(bar == 0); 705522Snate@binkert.org 715522Snate@binkert.org DPRINTF(VIOPci, "Reading offset 0x%x [len: %i]\n", offset, size); 725522Snate@binkert.org 735522Snate@binkert.org // Forward device configuration writes to the device VirtIO model 745604Snate@binkert.org if (offset >= OFF_VIO_DEVICE) { 755604Snate@binkert.org vio.readConfig(pkt, offset - OFF_VIO_DEVICE); 764762Snate@binkert.org return 0; 774762Snate@binkert.org } 784762Snate@binkert.org 794762Snate@binkert.org pkt->makeResponse(); 805522Snate@binkert.org 814762Snate@binkert.org switch(offset) { 824762Snate@binkert.org case OFF_DEVICE_FEATURES: 835604Snate@binkert.org DPRINTF(VIOPci, " DEVICE_FEATURES request\n"); 845604Snate@binkert.org assert(size == sizeof(uint32_t)); 855604Snate@binkert.org pkt->set<uint32_t>(vio.deviceFeatures); 865604Snate@binkert.org break; 875604Snate@binkert.org 885604Snate@binkert.org case OFF_GUEST_FEATURES: 894762Snate@binkert.org DPRINTF(VIOPci, " GUEST_FEATURES request\n"); 904762Snate@binkert.org assert(size == sizeof(uint32_t)); 914762Snate@binkert.org pkt->set<uint32_t>(vio.getGuestFeatures()); 924762Snate@binkert.org break; 935604Snate@binkert.org 944762Snate@binkert.org case OFF_QUEUE_ADDRESS: 955522Snate@binkert.org DPRINTF(VIOPci, " QUEUE_ADDRESS request\n"); 965522Snate@binkert.org assert(size == sizeof(uint32_t)); 975522Snate@binkert.org pkt->set<uint32_t>(vio.getQueueAddress()); 984762Snate@binkert.org break; 994382Sbinkertn@umich.edu 1004762Snate@binkert.org case OFF_QUEUE_SIZE: 1014382Sbinkertn@umich.edu DPRINTF(VIOPci, " QUEUE_SIZE request\n"); 1025522Snate@binkert.org assert(size == sizeof(uint16_t)); 1034381Sbinkertn@umich.edu pkt->set<uint16_t>(vio.getQueueSize()); 1045522Snate@binkert.org break; 1054762Snate@binkert.org 1064762Snate@binkert.org case OFF_QUEUE_SELECT: 1074762Snate@binkert.org DPRINTF(VIOPci, " QUEUE_SELECT\n"); 1085522Snate@binkert.org assert(size == sizeof(uint16_t)); 1095522Snate@binkert.org pkt->set<uint16_t>(vio.getQueueSelect()); 1105522Snate@binkert.org break; 1115522Snate@binkert.org 1125522Snate@binkert.org case OFF_QUEUE_NOTIFY: 1135522Snate@binkert.org DPRINTF(VIOPci, " QUEUE_NOTIFY request\n"); 1145522Snate@binkert.org assert(size == sizeof(uint16_t)); 1155522Snate@binkert.org pkt->set<uint16_t>(queueNotify); 1165522Snate@binkert.org break; 1174762Snate@binkert.org 1184762Snate@binkert.org case OFF_DEVICE_STATUS: 1194762Snate@binkert.org DPRINTF(VIOPci, " DEVICE_STATUS request\n"); 1204762Snate@binkert.org assert(size == sizeof(uint8_t)); 1214762Snate@binkert.org pkt->set<uint8_t>(vio.getDeviceStatus()); 1224762Snate@binkert.org break; 1234762Snate@binkert.org 1244762Snate@binkert.org case OFF_ISR_STATUS: { 1254762Snate@binkert.org DPRINTF(VIOPci, " ISR_STATUS\n"); 1264762Snate@binkert.org assert(size == sizeof(uint8_t)); 1274762Snate@binkert.org const uint8_t isr_status(interruptDeliveryPending ? 1 : 0); 1284762Snate@binkert.org if (interruptDeliveryPending) { 1294762Snate@binkert.org interruptDeliveryPending = false; 1304762Snate@binkert.org intrClear(); 1314762Snate@binkert.org } 1324762Snate@binkert.org pkt->set<uint8_t>(isr_status); 1334762Snate@binkert.org } break; 1344762Snate@binkert.org 1354762Snate@binkert.org default: 1364762Snate@binkert.org panic("Unhandled read offset (0x%x)\n", offset); 1374762Snate@binkert.org } 1384762Snate@binkert.org 1394762Snate@binkert.org return 0; 1404762Snate@binkert.org} 1414762Snate@binkert.org 1424762Snate@binkert.orgTick 1434762Snate@binkert.orgPciVirtIO::write(PacketPtr pkt) 1444762Snate@binkert.org{ 1454762Snate@binkert.org const unsigned M5_VAR_USED size(pkt->getSize()); 1464762Snate@binkert.org int bar; 1474762Snate@binkert.org Addr offset; 1484762Snate@binkert.org if (!getBAR(pkt->getAddr(), bar, offset)) 1494762Snate@binkert.org panic("Invalid PCI memory access to unmapped memory.\n"); 1504762Snate@binkert.org assert(bar == 0); 1514762Snate@binkert.org 152955SN/A DPRINTF(VIOPci, "Writing offset 0x%x [len: %i]\n", offset, size); 1535584Snate@binkert.org 1545584Snate@binkert.org // Forward device configuration writes to the device VirtIO model 1555584Snate@binkert.org if (offset >= OFF_VIO_DEVICE) { 1565584Snate@binkert.org vio.writeConfig(pkt, offset - OFF_VIO_DEVICE); 1575584Snate@binkert.org return 0; 1585584Snate@binkert.org } 1595584Snate@binkert.org 1605584Snate@binkert.org pkt->makeResponse(); 1615584Snate@binkert.org 1625584Snate@binkert.org switch(offset) { 1635584Snate@binkert.org case OFF_DEVICE_FEATURES: 1645584Snate@binkert.org warn("Guest tried to write device features."); 1655584Snate@binkert.org break; 1664382Sbinkertn@umich.edu 1674202Sbinkertn@umich.edu case OFF_GUEST_FEATURES: 1685522Snate@binkert.org DPRINTF(VIOPci, " WRITE GUEST_FEATURES request\n"); 1694382Sbinkertn@umich.edu assert(size == sizeof(uint32_t)); 1704382Sbinkertn@umich.edu vio.setGuestFeatures(pkt->get<uint32_t>()); 1714382Sbinkertn@umich.edu break; 1725584Snate@binkert.org 1734382Sbinkertn@umich.edu case OFF_QUEUE_ADDRESS: 1744382Sbinkertn@umich.edu DPRINTF(VIOPci, " WRITE QUEUE_ADDRESS\n"); 1754382Sbinkertn@umich.edu assert(size == sizeof(uint32_t)); 1765192Ssaidi@eecs.umich.edu vio.setQueueAddress(pkt->get<uint32_t>()); 1775192Ssaidi@eecs.umich.edu break; 1785799Snate@binkert.org 1795799Snate@binkert.org case OFF_QUEUE_SIZE: 1805799Snate@binkert.org panic("Guest tried to write queue size."); 1815192Ssaidi@eecs.umich.edu break; 1825799Snate@binkert.org 1835192Ssaidi@eecs.umich.edu case OFF_QUEUE_SELECT: 1845799Snate@binkert.org DPRINTF(VIOPci, " WRITE QUEUE_SELECT\n"); 1855799Snate@binkert.org assert(size == sizeof(uint16_t)); 1865192Ssaidi@eecs.umich.edu vio.setQueueSelect(pkt->get<uint16_t>()); 1875192Ssaidi@eecs.umich.edu break; 1885192Ssaidi@eecs.umich.edu 1895192Ssaidi@eecs.umich.edu case OFF_QUEUE_NOTIFY: 1905799Snate@binkert.org DPRINTF(VIOPci, " WRITE QUEUE_NOTIFY\n"); 1915192Ssaidi@eecs.umich.edu assert(size == sizeof(uint16_t)); 1925799Snate@binkert.org queueNotify = pkt->get<uint16_t>(); 1935192Ssaidi@eecs.umich.edu vio.onNotify(queueNotify); 1945192Ssaidi@eecs.umich.edu break; 1955192Ssaidi@eecs.umich.edu 1965799Snate@binkert.org case OFF_DEVICE_STATUS: { 1975192Ssaidi@eecs.umich.edu assert(size == sizeof(uint8_t)); 1985192Ssaidi@eecs.umich.edu uint8_t status(pkt->get<uint8_t>()); 1995192Ssaidi@eecs.umich.edu DPRINTF(VIOPci, "VirtIO set status: 0x%x\n", status); 2005192Ssaidi@eecs.umich.edu vio.setDeviceStatus(status); 2015192Ssaidi@eecs.umich.edu } break; 2025192Ssaidi@eecs.umich.edu 2034382Sbinkertn@umich.edu case OFF_ISR_STATUS: 2044382Sbinkertn@umich.edu warn("Guest tried to write ISR status."); 2054382Sbinkertn@umich.edu break; 2062667Sstever@eecs.umich.edu 2072667Sstever@eecs.umich.edu default: 2082667Sstever@eecs.umich.edu panic("Unhandled read offset (0x%x)\n", offset); 2092667Sstever@eecs.umich.edu } 2102667Sstever@eecs.umich.edu 2112667Sstever@eecs.umich.edu return 0; 2125742Snate@binkert.org} 2135742Snate@binkert.org 2145742Snate@binkert.orgvoid 2152037SN/APciVirtIO::kick() 2162037SN/A{ 2172037SN/A DPRINTF(VIOPci, "kick(): Sending interrupt...\n"); 2185793Snate@binkert.org interruptDeliveryPending = true; 2195793Snate@binkert.org intrPost(); 2205793Snate@binkert.org} 2215793Snate@binkert.org 2225793Snate@binkert.orgPciVirtIO * 2234382Sbinkertn@umich.eduPciVirtIOParams::create() 2244762Snate@binkert.org{ 2255344Sstever@gmail.com return new PciVirtIO(this); 2264382Sbinkertn@umich.edu} 2275341Sstever@gmail.com