pci.cc revision 10672:e2716d523716
1196Sstever@eecs.umich.edu/* 22Ssraasch@umich.edu * Copyright (c) 2014 ARM Limited 3196Sstever@eecs.umich.edu * All rights reserved 42Ssraasch@umich.edu * 52Ssraasch@umich.edu * The license below extends only to copyright in the software and shall 6196Sstever@eecs.umich.edu * not be construed as granting a license to any other intellectual 7196Sstever@eecs.umich.edu * property including but not limited to intellectual property relating 8196Sstever@eecs.umich.edu * to a hardware implementation of the functionality of the software 9196Sstever@eecs.umich.edu * licensed hereunder. You may use the software subject to the license 10196Sstever@eecs.umich.edu * terms below provided that you ensure that this notice is replicated 11196Sstever@eecs.umich.edu * unmodified and in its entirety in all distributions of the software, 12196Sstever@eecs.umich.edu * modified or unmodified, in source code or in binary form. 13196Sstever@eecs.umich.edu * 14196Sstever@eecs.umich.edu * Redistribution and use in source and binary forms, with or without 15196Sstever@eecs.umich.edu * modification, are permitted provided that the following conditions are 162Ssraasch@umich.edu * met: redistributions of source code must retain the above copyright 17196Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer; 18196Sstever@eecs.umich.edu * redistributions in binary form must reproduce the above copyright 19196Sstever@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the 20196Sstever@eecs.umich.edu * documentation and/or other materials provided with the distribution; 21196Sstever@eecs.umich.edu * neither the name of the copyright holders nor the names of its 22196Sstever@eecs.umich.edu * contributors may be used to endorse or promote products derived from 23196Sstever@eecs.umich.edu * this software without specific prior written permission. 24196Sstever@eecs.umich.edu * 25196Sstever@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26196Sstever@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27196Sstever@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28196Sstever@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29196Sstever@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302Ssraasch@umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31196Sstever@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32196Sstever@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33196Sstever@eecs.umich.edu * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34196Sstever@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35196Sstever@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36196Sstever@eecs.umich.edu * 37196Sstever@eecs.umich.edu * Authors: Andreas Sandberg 38196Sstever@eecs.umich.edu */ 39196Sstever@eecs.umich.edu 402Ssraasch@umich.edu#include "debug/VIOPci.hh" 412Ssraasch@umich.edu#include "dev/virtio/pci.hh" 42196Sstever@eecs.umich.edu#include "mem/packet_access.hh" 432Ssraasch@umich.edu#include "params/PciVirtIO.hh" 44196Sstever@eecs.umich.edu 45196Sstever@eecs.umich.eduPciVirtIO::PciVirtIO(const Params *params) 46196Sstever@eecs.umich.edu : PciDevice(params), queueNotify(0), interruptDeliveryPending(false), 47196Sstever@eecs.umich.edu vio(*params->vio), callbackKick(this) 48196Sstever@eecs.umich.edu{ 49196Sstever@eecs.umich.edu // Override the subsystem ID with the device ID from VirtIO 50196Sstever@eecs.umich.edu config.subsystemID = htole(vio.deviceId); 512Ssraasch@umich.edu BARSize[0] = BAR0_SIZE_BASE + vio.configSize; 52196Sstever@eecs.umich.edu 53196Sstever@eecs.umich.edu vio.registerKickCallback(&callbackKick); 54196Sstever@eecs.umich.edu} 552Ssraasch@umich.edu 56196Sstever@eecs.umich.eduPciVirtIO::~PciVirtIO() 57196Sstever@eecs.umich.edu{ 58196Sstever@eecs.umich.edu} 592Ssraasch@umich.edu 60196Sstever@eecs.umich.eduTick 61196Sstever@eecs.umich.eduPciVirtIO::read(PacketPtr pkt) 622Ssraasch@umich.edu{ 63196Sstever@eecs.umich.edu const unsigned M5_VAR_USED size(pkt->getSize()); 642Ssraasch@umich.edu int bar; 65196Sstever@eecs.umich.edu Addr offset; 66196Sstever@eecs.umich.edu if (!getBAR(pkt->getAddr(), bar, offset)) 67196Sstever@eecs.umich.edu panic("Invalid PCI memory access to unmapped memory.\n"); 682Ssraasch@umich.edu assert(bar == 0); 69196Sstever@eecs.umich.edu 70196Sstever@eecs.umich.edu DPRINTF(VIOPci, "Reading offset 0x%x [len: %i]\n", offset, size); 71196Sstever@eecs.umich.edu 72196Sstever@eecs.umich.edu // Forward device configuration writes to the device VirtIO model 732Ssraasch@umich.edu if (offset >= OFF_VIO_DEVICE) { 74196Sstever@eecs.umich.edu vio.readConfig(pkt, offset - OFF_VIO_DEVICE); 75196Sstever@eecs.umich.edu return 0; 76196Sstever@eecs.umich.edu } 772Ssraasch@umich.edu 78196Sstever@eecs.umich.edu pkt->makeResponse(); 79196Sstever@eecs.umich.edu 80196Sstever@eecs.umich.edu switch(offset) { 81196Sstever@eecs.umich.edu case OFF_DEVICE_FEATURES: 82196Sstever@eecs.umich.edu DPRINTF(VIOPci, " DEVICE_FEATURES request\n"); 832Ssraasch@umich.edu assert(size == sizeof(uint32_t)); 84196Sstever@eecs.umich.edu pkt->set<uint32_t>(vio.deviceFeatures); 85196Sstever@eecs.umich.edu break; 86196Sstever@eecs.umich.edu 87196Sstever@eecs.umich.edu case OFF_GUEST_FEATURES: 882Ssraasch@umich.edu DPRINTF(VIOPci, " GUEST_FEATURES request\n"); 89196Sstever@eecs.umich.edu assert(size == sizeof(uint32_t)); 90196Sstever@eecs.umich.edu pkt->set<uint32_t>(vio.getGuestFeatures()); 91196Sstever@eecs.umich.edu break; 92196Sstever@eecs.umich.edu 932Ssraasch@umich.edu case OFF_QUEUE_ADDRESS: 942Ssraasch@umich.edu DPRINTF(VIOPci, " QUEUE_ADDRESS request\n"); 952Ssraasch@umich.edu assert(size == sizeof(uint32_t)); 96196Sstever@eecs.umich.edu pkt->set<uint32_t>(vio.getQueueAddress()); 97196Sstever@eecs.umich.edu break; 98196Sstever@eecs.umich.edu 99196Sstever@eecs.umich.edu case OFF_QUEUE_SIZE: 1002Ssraasch@umich.edu DPRINTF(VIOPci, " QUEUE_SIZE request\n"); 101196Sstever@eecs.umich.edu assert(size == sizeof(uint16_t)); 102196Sstever@eecs.umich.edu pkt->set<uint16_t>(vio.getQueueSize()); 103196Sstever@eecs.umich.edu break; 104196Sstever@eecs.umich.edu 105196Sstever@eecs.umich.edu case OFF_QUEUE_SELECT: 1062Ssraasch@umich.edu DPRINTF(VIOPci, " QUEUE_SELECT\n"); 1072Ssraasch@umich.edu assert(size == sizeof(uint16_t)); 108196Sstever@eecs.umich.edu pkt->set<uint16_t>(vio.getQueueSelect()); 109196Sstever@eecs.umich.edu break; 110196Sstever@eecs.umich.edu 111196Sstever@eecs.umich.edu case OFF_QUEUE_NOTIFY: 112196Sstever@eecs.umich.edu DPRINTF(VIOPci, " QUEUE_NOTIFY request\n"); 1132Ssraasch@umich.edu assert(size == sizeof(uint16_t)); 114196Sstever@eecs.umich.edu pkt->set<uint16_t>(queueNotify); 115196Sstever@eecs.umich.edu break; 116196Sstever@eecs.umich.edu 117196Sstever@eecs.umich.edu case OFF_DEVICE_STATUS: 118196Sstever@eecs.umich.edu DPRINTF(VIOPci, " DEVICE_STATUS request\n"); 119196Sstever@eecs.umich.edu assert(size == sizeof(uint8_t)); 120196Sstever@eecs.umich.edu pkt->set<uint8_t>(vio.getDeviceStatus()); 121196Sstever@eecs.umich.edu break; 1222Ssraasch@umich.edu 1232Ssraasch@umich.edu case OFF_ISR_STATUS: { 124196Sstever@eecs.umich.edu DPRINTF(VIOPci, " ISR_STATUS\n"); 125196Sstever@eecs.umich.edu assert(size == sizeof(uint8_t)); 126196Sstever@eecs.umich.edu const uint8_t isr_status(interruptDeliveryPending ? 1 : 0); 127196Sstever@eecs.umich.edu if (interruptDeliveryPending) { 128196Sstever@eecs.umich.edu interruptDeliveryPending = false; 129196Sstever@eecs.umich.edu intrClear(); 130196Sstever@eecs.umich.edu } 1312Ssraasch@umich.edu pkt->set<uint8_t>(isr_status); 132196Sstever@eecs.umich.edu } break; 133196Sstever@eecs.umich.edu 134196Sstever@eecs.umich.edu default: 135196Sstever@eecs.umich.edu panic("Unhandled read offset (0x%x)\n", offset); 136196Sstever@eecs.umich.edu } 137196Sstever@eecs.umich.edu 138196Sstever@eecs.umich.edu return 0; 139196Sstever@eecs.umich.edu} 1402Ssraasch@umich.edu 1412Ssraasch@umich.eduTick 1422Ssraasch@umich.eduPciVirtIO::write(PacketPtr pkt) 143196Sstever@eecs.umich.edu{ 144196Sstever@eecs.umich.edu const unsigned M5_VAR_USED size(pkt->getSize()); 145196Sstever@eecs.umich.edu int bar; 146196Sstever@eecs.umich.edu Addr offset; 147196Sstever@eecs.umich.edu if (!getBAR(pkt->getAddr(), bar, offset)) 1482Ssraasch@umich.edu panic("Invalid PCI memory access to unmapped memory.\n"); 149196Sstever@eecs.umich.edu assert(bar == 0); 150196Sstever@eecs.umich.edu 151196Sstever@eecs.umich.edu DPRINTF(VIOPci, "Writing offset 0x%x [len: %i]\n", offset, size); 152196Sstever@eecs.umich.edu 153196Sstever@eecs.umich.edu // Forward device configuration writes to the device VirtIO model 154196Sstever@eecs.umich.edu if (offset >= OFF_VIO_DEVICE) { 155196Sstever@eecs.umich.edu vio.writeConfig(pkt, offset - OFF_VIO_DEVICE); 156196Sstever@eecs.umich.edu return 0; 157196Sstever@eecs.umich.edu } 158196Sstever@eecs.umich.edu 159196Sstever@eecs.umich.edu pkt->makeResponse(); 160196Sstever@eecs.umich.edu 161196Sstever@eecs.umich.edu switch(offset) { 162196Sstever@eecs.umich.edu case OFF_DEVICE_FEATURES: 163196Sstever@eecs.umich.edu warn("Guest tried to write device features."); 164196Sstever@eecs.umich.edu break; 165196Sstever@eecs.umich.edu 166196Sstever@eecs.umich.edu case OFF_GUEST_FEATURES: 167196Sstever@eecs.umich.edu DPRINTF(VIOPci, " WRITE GUEST_FEATURES request\n"); 168196Sstever@eecs.umich.edu assert(size == sizeof(uint32_t)); 169196Sstever@eecs.umich.edu vio.setGuestFeatures(pkt->get<uint32_t>()); 170196Sstever@eecs.umich.edu break; 171196Sstever@eecs.umich.edu 172196Sstever@eecs.umich.edu case OFF_QUEUE_ADDRESS: 173196Sstever@eecs.umich.edu DPRINTF(VIOPci, " WRITE QUEUE_ADDRESS\n"); 174196Sstever@eecs.umich.edu assert(size == sizeof(uint32_t)); 175196Sstever@eecs.umich.edu vio.setQueueAddress(pkt->get<uint32_t>()); 176196Sstever@eecs.umich.edu break; 177196Sstever@eecs.umich.edu 178196Sstever@eecs.umich.edu case OFF_QUEUE_SIZE: 179196Sstever@eecs.umich.edu panic("Guest tried to write queue size."); 180196Sstever@eecs.umich.edu break; 181196Sstever@eecs.umich.edu 1822Ssraasch@umich.edu case OFF_QUEUE_SELECT: 1832Ssraasch@umich.edu DPRINTF(VIOPci, " WRITE QUEUE_SELECT\n"); 184196Sstever@eecs.umich.edu assert(size == sizeof(uint16_t)); 185196Sstever@eecs.umich.edu vio.setQueueSelect(pkt->get<uint16_t>()); 186196Sstever@eecs.umich.edu break; 187196Sstever@eecs.umich.edu 188196Sstever@eecs.umich.edu case OFF_QUEUE_NOTIFY: 1892Ssraasch@umich.edu DPRINTF(VIOPci, " WRITE QUEUE_NOTIFY\n"); 190196Sstever@eecs.umich.edu assert(size == sizeof(uint16_t)); 191196Sstever@eecs.umich.edu queueNotify = pkt->get<uint16_t>(); 192196Sstever@eecs.umich.edu vio.onNotify(queueNotify); 193196Sstever@eecs.umich.edu break; 194196Sstever@eecs.umich.edu 1952Ssraasch@umich.edu case OFF_DEVICE_STATUS: { 196196Sstever@eecs.umich.edu assert(size == sizeof(uint8_t)); 197196Sstever@eecs.umich.edu uint8_t status(pkt->get<uint8_t>()); 198196Sstever@eecs.umich.edu DPRINTF(VIOPci, "VirtIO set status: 0x%x\n", status); 199196Sstever@eecs.umich.edu vio.setDeviceStatus(status); 200196Sstever@eecs.umich.edu } break; 201196Sstever@eecs.umich.edu 202196Sstever@eecs.umich.edu case OFF_ISR_STATUS: 203196Sstever@eecs.umich.edu warn("Guest tried to write ISR status."); 204196Sstever@eecs.umich.edu break; 205196Sstever@eecs.umich.edu 206196Sstever@eecs.umich.edu default: 207196Sstever@eecs.umich.edu panic("Unhandled read offset (0x%x)\n", offset); 208196Sstever@eecs.umich.edu } 209196Sstever@eecs.umich.edu 210196Sstever@eecs.umich.edu return 0; 211196Sstever@eecs.umich.edu} 212196Sstever@eecs.umich.edu 213196Sstever@eecs.umich.eduvoid 214196Sstever@eecs.umich.eduPciVirtIO::kick() 215196Sstever@eecs.umich.edu{ 216196Sstever@eecs.umich.edu DPRINTF(VIOPci, "kick(): Sending interrupt...\n"); 217196Sstever@eecs.umich.edu interruptDeliveryPending = true; 218196Sstever@eecs.umich.edu intrPost(); 219196Sstever@eecs.umich.edu} 220196Sstever@eecs.umich.edu 221196Sstever@eecs.umich.eduPciVirtIO * 222196Sstever@eecs.umich.eduPciVirtIOParams::create() 223196Sstever@eecs.umich.edu{ 224196Sstever@eecs.umich.edu return new PciVirtIO(this); 225196Sstever@eecs.umich.edu} 226196Sstever@eecs.umich.edu