pci.cc revision 10672:e2716d523716
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          const uint8_t isr_status(interruptDeliveryPending ? 1 : 0);
127          if (interruptDeliveryPending) {
128              interruptDeliveryPending = false;
129              intrClear();
130          }
131          pkt->set<uint8_t>(isr_status);
132      } break;
133
134      default:
135        panic("Unhandled read offset (0x%x)\n", offset);
136    }
137
138    return 0;
139}
140
141Tick
142PciVirtIO::write(PacketPtr pkt)
143{
144    const unsigned M5_VAR_USED size(pkt->getSize());
145    int bar;
146    Addr offset;
147    if (!getBAR(pkt->getAddr(), bar, offset))
148        panic("Invalid PCI memory access to unmapped memory.\n");
149    assert(bar == 0);
150
151    DPRINTF(VIOPci, "Writing offset 0x%x [len: %i]\n", offset, size);
152
153    // Forward device configuration writes to the device VirtIO model
154    if (offset >= OFF_VIO_DEVICE) {
155        vio.writeConfig(pkt, offset - OFF_VIO_DEVICE);
156        return 0;
157    }
158
159    pkt->makeResponse();
160
161    switch(offset) {
162      case OFF_DEVICE_FEATURES:
163        warn("Guest tried to write device features.");
164        break;
165
166      case OFF_GUEST_FEATURES:
167        DPRINTF(VIOPci, "   WRITE GUEST_FEATURES request\n");
168        assert(size == sizeof(uint32_t));
169        vio.setGuestFeatures(pkt->get<uint32_t>());
170        break;
171
172      case OFF_QUEUE_ADDRESS:
173        DPRINTF(VIOPci, "   WRITE QUEUE_ADDRESS\n");
174        assert(size == sizeof(uint32_t));
175        vio.setQueueAddress(pkt->get<uint32_t>());
176        break;
177
178      case OFF_QUEUE_SIZE:
179        panic("Guest tried to write queue size.");
180        break;
181
182      case OFF_QUEUE_SELECT:
183        DPRINTF(VIOPci, "   WRITE QUEUE_SELECT\n");
184        assert(size == sizeof(uint16_t));
185        vio.setQueueSelect(pkt->get<uint16_t>());
186        break;
187
188      case OFF_QUEUE_NOTIFY:
189        DPRINTF(VIOPci, "   WRITE QUEUE_NOTIFY\n");
190        assert(size == sizeof(uint16_t));
191        queueNotify = pkt->get<uint16_t>();
192        vio.onNotify(queueNotify);
193        break;
194
195      case OFF_DEVICE_STATUS: {
196          assert(size == sizeof(uint8_t));
197          uint8_t status(pkt->get<uint8_t>());
198          DPRINTF(VIOPci, "VirtIO set status: 0x%x\n", status);
199          vio.setDeviceStatus(status);
200      } break;
201
202      case OFF_ISR_STATUS:
203        warn("Guest tried to write ISR status.");
204        break;
205
206      default:
207        panic("Unhandled read offset (0x%x)\n", offset);
208    }
209
210    return 0;
211}
212
213void
214PciVirtIO::kick()
215{
216    DPRINTF(VIOPci, "kick(): Sending interrupt...\n");
217    interruptDeliveryPending = true;
218    intrPost();
219}
220
221PciVirtIO *
222PciVirtIOParams::create()
223{
224    return new PciVirtIO(this);
225}
226