pci.cc revision 10602
1/*
2 * Copyright (c) 2014 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Andreas Sandberg
38 */
39
40#include "debug/VIOPci.hh"
41#include "dev/virtio/pci.hh"
42#include "mem/packet_access.hh"
43#include "params/PciVirtIO.hh"
44
45PciVirtIO::PciVirtIO(const Params *params)
46    : PciDevice(params), queueNotify(0), interruptDeliveryPending(false),
47      vio(*params->vio), callbackKick(this)
48{
49    // Override the subsystem ID with the device ID from VirtIO
50    config.subsystemID = htole(vio.deviceId);
51    BARSize[0] = BAR0_SIZE_BASE + vio.configSize;
52
53    vio.registerKickCallback(&callbackKick);
54}
55
56PciVirtIO::~PciVirtIO()
57{
58}
59
60Tick
61PciVirtIO::read(PacketPtr pkt)
62{
63    const unsigned M5_VAR_USED size(pkt->getSize());
64    int bar;
65    Addr offset;
66    if (!getBAR(pkt->getAddr(), bar, offset))
67        panic("Invalid PCI memory access to unmapped memory.\n");
68    assert(bar == 0);
69
70    DPRINTF(VIOPci, "Reading offset 0x%x [len: %i]\n", offset, size);
71
72    // Forward device configuration writes to the device VirtIO model
73    if (offset >= OFF_VIO_DEVICE) {
74        vio.readConfig(pkt, offset - OFF_VIO_DEVICE);
75        return 0;
76    }
77
78    pkt->makeResponse();
79
80    switch(offset) {
81      case OFF_DEVICE_FEATURES:
82        DPRINTF(VIOPci, "   DEVICE_FEATURES request\n");
83        assert(size == sizeof(uint32_t));
84        pkt->set<uint32_t>(vio.deviceFeatures);
85        break;
86
87      case OFF_GUEST_FEATURES:
88        DPRINTF(VIOPci, "   GUEST_FEATURES request\n");
89        assert(size == sizeof(uint32_t));
90        pkt->set<uint32_t>(vio.getGuestFeatures());
91        break;
92
93      case OFF_QUEUE_ADDRESS:
94        DPRINTF(VIOPci, "   QUEUE_ADDRESS request\n");
95        assert(size == sizeof(uint32_t));
96        pkt->set<uint32_t>(vio.getQueueAddress());
97        break;
98
99      case OFF_QUEUE_SIZE:
100        DPRINTF(VIOPci, "   QUEUE_SIZE request\n");
101        assert(size == sizeof(uint16_t));
102        pkt->set<uint16_t>(vio.getQueueSize());
103        break;
104
105      case OFF_QUEUE_SELECT:
106        DPRINTF(VIOPci, "   QUEUE_SELECT\n");
107        assert(size == sizeof(uint16_t));
108        pkt->set<uint16_t>(vio.getQueueSelect());
109        break;
110
111      case OFF_QUEUE_NOTIFY:
112        DPRINTF(VIOPci, "   QUEUE_NOTIFY request\n");
113        assert(size == sizeof(uint16_t));
114        pkt->set<uint16_t>(queueNotify);
115        break;
116
117      case OFF_DEVICE_STATUS:
118        DPRINTF(VIOPci, "   DEVICE_STATUS request\n");
119        assert(size == sizeof(uint8_t));
120        pkt->set<uint8_t>(vio.getDeviceStatus());
121        break;
122
123      case OFF_ISR_STATUS: {
124          DPRINTF(VIOPci, "   ISR_STATUS\n");
125          assert(size == sizeof(uint8_t));
126          uint8_t isr_status(interruptDeliveryPending ? 1 : 0);
127          interruptDeliveryPending = false;
128          pkt->set<uint8_t>(isr_status);
129      } break;
130
131      default:
132        panic("Unhandled read offset (0x%x)\n", offset);
133    }
134
135    return 0;
136}
137
138Tick
139PciVirtIO::write(PacketPtr pkt)
140{
141    const unsigned M5_VAR_USED size(pkt->getSize());
142    int bar;
143    Addr offset;
144    if (!getBAR(pkt->getAddr(), bar, offset))
145        panic("Invalid PCI memory access to unmapped memory.\n");
146    assert(bar == 0);
147
148    DPRINTF(VIOPci, "Writing offset 0x%x [len: %i]\n", offset, size);
149
150    // Forward device configuration writes to the device VirtIO model
151    if (offset >= OFF_VIO_DEVICE) {
152        vio.writeConfig(pkt, offset - OFF_VIO_DEVICE);
153        return 0;
154    }
155
156    pkt->makeResponse();
157
158    switch(offset) {
159      case OFF_DEVICE_FEATURES:
160        warn("Guest tried to write device features.");
161        break;
162
163      case OFF_GUEST_FEATURES:
164        DPRINTF(VIOPci, "   WRITE GUEST_FEATURES request\n");
165        assert(size == sizeof(uint32_t));
166        vio.setGuestFeatures(pkt->get<uint32_t>());
167        break;
168
169      case OFF_QUEUE_ADDRESS:
170        DPRINTF(VIOPci, "   WRITE QUEUE_ADDRESS\n");
171        assert(size == sizeof(uint32_t));
172        vio.setQueueAddress(pkt->get<uint32_t>());
173        break;
174
175      case OFF_QUEUE_SIZE:
176        panic("Guest tried to write queue size.");
177        break;
178
179      case OFF_QUEUE_SELECT:
180        DPRINTF(VIOPci, "   WRITE QUEUE_SELECT\n");
181        assert(size == sizeof(uint16_t));
182        vio.setQueueSelect(pkt->get<uint16_t>());
183        break;
184
185      case OFF_QUEUE_NOTIFY:
186        DPRINTF(VIOPci, "   WRITE QUEUE_NOTIFY\n");
187        assert(size == sizeof(uint16_t));
188        queueNotify = pkt->get<uint16_t>();
189        vio.onNotify(queueNotify);
190        break;
191
192      case OFF_DEVICE_STATUS: {
193          assert(size == sizeof(uint8_t));
194          uint8_t status(pkt->get<uint8_t>());
195          DPRINTF(VIOPci, "VirtIO set status: 0x%x\n", status);
196          vio.setDeviceStatus(status);
197      } break;
198
199      case OFF_ISR_STATUS:
200        warn("Guest tried to write ISR status.");
201        break;
202
203      default:
204        panic("Unhandled read offset (0x%x)\n", offset);
205    }
206
207    return 0;
208}
209
210void
211PciVirtIO::kick()
212{
213    DPRINTF(VIOPci, "kick(): Sending interrupt...\n");
214    interruptDeliveryPending = true;
215    intrPost();
216}
217
218PciVirtIO *
219PciVirtIOParams::create()
220{
221    return new PciVirtIO(this);
222}
223