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->allocate();
79
78 switch(offset) {
79 case OFF_DEVICE_FEATURES:
80 DPRINTF(VIOPci, " DEVICE_FEATURES request\n");
81 assert(size == sizeof(uint32_t));
82 pkt->set<uint32_t>(vio.deviceFeatures);
83 break;
84
85 case OFF_GUEST_FEATURES:
86 DPRINTF(VIOPci, " GUEST_FEATURES request\n");
87 assert(size == sizeof(uint32_t));
88 pkt->set<uint32_t>(vio.getGuestFeatures());
89 break;
90
91 case OFF_QUEUE_ADDRESS:
92 DPRINTF(VIOPci, " QUEUE_ADDRESS request\n");
93 assert(size == sizeof(uint32_t));
94 pkt->set<uint32_t>(vio.getQueueAddress());
95 break;
96
97 case OFF_QUEUE_SIZE:
98 DPRINTF(VIOPci, " QUEUE_SIZE request\n");
99 assert(size == sizeof(uint16_t));
100 pkt->set<uint16_t>(vio.getQueueSize());
101 break;
102
103 case OFF_QUEUE_SELECT:
104 DPRINTF(VIOPci, " QUEUE_SELECT\n");
105 assert(size == sizeof(uint16_t));
106 pkt->set<uint16_t>(vio.getQueueSelect());
107 break;
108
109 case OFF_QUEUE_NOTIFY:
110 DPRINTF(VIOPci, " QUEUE_NOTIFY request\n");
111 assert(size == sizeof(uint16_t));
112 pkt->set<uint16_t>(queueNotify);
113 break;
114
115 case OFF_DEVICE_STATUS:
116 DPRINTF(VIOPci, " DEVICE_STATUS request\n");
117 assert(size == sizeof(uint8_t));
118 pkt->set<uint8_t>(vio.getDeviceStatus());
119 break;
120
121 case OFF_ISR_STATUS: {
122 DPRINTF(VIOPci, " ISR_STATUS\n");
123 assert(size == sizeof(uint8_t));
124 uint8_t isr_status(interruptDeliveryPending ? 1 : 0);
125 interruptDeliveryPending = false;
126 pkt->set<uint8_t>(isr_status);
127 } break;
128
129 default:
130 panic("Unhandled read offset (0x%x)\n", offset);
131 }
132
133 return 0;
134}
135
136Tick
137PciVirtIO::write(PacketPtr pkt)
138{
139 const unsigned M5_VAR_USED size(pkt->getSize());
140 int bar;
141 Addr offset;
142 if (!getBAR(pkt->getAddr(), bar, offset))
143 panic("Invalid PCI memory access to unmapped memory.\n");
144 assert(bar == 0);
145
146 DPRINTF(VIOPci, "Writing offset 0x%x [len: %i]\n", offset, size);
147
148 // Forward device configuration writes to the device VirtIO model
149 if (offset >= OFF_VIO_DEVICE) {
150 vio.writeConfig(pkt, offset - OFF_VIO_DEVICE);
151 return 0;
152 }
153
156 pkt->allocate();
157
154 switch(offset) {
155 case OFF_DEVICE_FEATURES:
156 warn("Guest tried to write device features.");
157 break;
158
159 case OFF_GUEST_FEATURES:
160 DPRINTF(VIOPci, " WRITE GUEST_FEATURES request\n");
161 assert(size == sizeof(uint32_t));
162 vio.setGuestFeatures(pkt->get<uint32_t>());
163 break;
164
165 case OFF_QUEUE_ADDRESS:
166 DPRINTF(VIOPci, " WRITE QUEUE_ADDRESS\n");
167 assert(size == sizeof(uint32_t));
168 vio.setQueueAddress(pkt->get<uint32_t>());
169 break;
170
171 case OFF_QUEUE_SIZE:
172 panic("Guest tried to write queue size.");
173 break;
174
175 case OFF_QUEUE_SELECT:
176 DPRINTF(VIOPci, " WRITE QUEUE_SELECT\n");
177 assert(size == sizeof(uint16_t));
178 vio.setQueueSelect(pkt->get<uint16_t>());
179 break;
180
181 case OFF_QUEUE_NOTIFY:
182 DPRINTF(VIOPci, " WRITE QUEUE_NOTIFY\n");
183 assert(size == sizeof(uint16_t));
184 queueNotify = pkt->get<uint16_t>();
185 vio.onNotify(queueNotify);
186 break;
187
188 case OFF_DEVICE_STATUS: {
189 assert(size == sizeof(uint8_t));
190 uint8_t status(pkt->get<uint8_t>());
191 DPRINTF(VIOPci, "VirtIO set status: 0x%x\n", status);
192 vio.setDeviceStatus(status);
193 } break;
194
195 case OFF_ISR_STATUS:
196 warn("Guest tried to write ISR status.");
197 break;
198
199 default:
200 panic("Unhandled read offset (0x%x)\n", offset);
201 }
202
203 return 0;
204}
205
206void
207PciVirtIO::kick()
208{
209 DPRINTF(VIOPci, "kick(): Sending interrupt...\n");
210 interruptDeliveryPending = true;
211 intrPost();
212}
213
214PciVirtIO *
215PciVirtIOParams::create()
216{
217 return new PciVirtIO(this);
218}