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