dev: Delete the authors list from files in src/dev.
[gem5.git] / src / dev / arm / vio_mmio.cc
1 /*
2 * Copyright (c) 2016-2018 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
38 #include "dev/arm/vio_mmio.hh"
39
40 #include "debug/VIOIface.hh"
41 #include "dev/arm/base_gic.hh"
42 #include "mem/packet_access.hh"
43 #include "params/MmioVirtIO.hh"
44
45 MmioVirtIO::MmioVirtIO(const MmioVirtIOParams *params)
46 : BasicPioDevice(params, params->pio_size),
47 hostFeaturesSelect(0), guestFeaturesSelect(0), pageSize(0),
48 interruptStatus(0),
49 callbackKick(this), vio(*params->vio),
50 interrupt(params->interrupt->get())
51 {
52 fatal_if(!interrupt, "No MMIO VirtIO interrupt specified\n");
53
54 vio.registerKickCallback(&callbackKick);
55 }
56
57 MmioVirtIO::~MmioVirtIO()
58 {
59 }
60
61 Tick
62 MmioVirtIO::read(PacketPtr pkt)
63 {
64 const Addr offset = pkt->getAddr() - pioAddr;
65 const unsigned size(pkt->getSize());
66
67 DPRINTF(VIOIface, "Reading %u bytes @ 0x%x:\n", size, offset);
68
69 // Forward device configuration writes to the device VirtIO model
70 if (offset >= OFF_CONFIG) {
71 vio.readConfig(pkt, offset - OFF_CONFIG);
72 return 0;
73 }
74
75 panic_if(size != 4, "Unexpected read size: %u\n", size);
76
77 const uint32_t value = read(offset);
78 DPRINTF(VIOIface, " value: 0x%x\n", value);
79 pkt->makeResponse();
80 pkt->setLE<uint32_t>(value);
81
82 return 0;
83 }
84
85 uint32_t
86 MmioVirtIO::read(Addr offset)
87 {
88 switch(offset) {
89 case OFF_MAGIC:
90 return MAGIC;
91
92 case OFF_VERSION:
93 return VERSION;
94
95 case OFF_DEVICE_ID:
96 return vio.deviceId;
97
98 case OFF_VENDOR_ID:
99 return VENDOR_ID;
100
101 case OFF_HOST_FEATURES:
102 // We only implement 32 bits of this register
103 if (hostFeaturesSelect == 0)
104 return vio.deviceFeatures;
105 else
106 return 0;
107
108 case OFF_HOST_FEATURES_SELECT:
109 return hostFeaturesSelect;
110
111 case OFF_GUEST_FEATURES:
112 // We only implement 32 bits of this register
113 if (guestFeaturesSelect == 0)
114 return vio.getGuestFeatures();
115 else
116 return 0;
117
118 case OFF_GUEST_FEATURES_SELECT:
119 return hostFeaturesSelect;
120
121 case OFF_GUEST_PAGE_SIZE:
122 return pageSize;
123
124 case OFF_QUEUE_SELECT:
125 return vio.getQueueSelect();
126
127 case OFF_QUEUE_NUM_MAX:
128 return vio.getQueueSize();
129
130 case OFF_QUEUE_NUM:
131 // TODO: We don't support queue resizing, so ignore this for now.
132 return vio.getQueueSize();
133
134 case OFF_QUEUE_ALIGN:
135 // TODO: Implement this once we support other alignment sizes
136 return VirtQueue::ALIGN_SIZE;
137
138 case OFF_QUEUE_PFN:
139 return vio.getQueueAddress();
140
141 case OFF_INTERRUPT_STATUS:
142 return interruptStatus;
143
144 case OFF_STATUS:
145 return vio.getDeviceStatus();
146
147 // Write-only registers
148 case OFF_QUEUE_NOTIFY:
149 case OFF_INTERRUPT_ACK:
150 warn("Guest is trying to read to write-only register 0x%\n",
151 offset);
152 return 0;
153
154 default:
155 panic("Unhandled read offset (0x%x)\n", offset);
156 }
157 }
158
159 Tick
160 MmioVirtIO::write(PacketPtr pkt)
161 {
162 const Addr offset = pkt->getAddr() - pioAddr;
163 const unsigned size(pkt->getSize());
164
165 DPRINTF(VIOIface, "Writing %u bytes @ 0x%x:\n", size, offset);
166
167 // Forward device configuration writes to the device VirtIO model
168 if (offset >= OFF_CONFIG) {
169 vio.writeConfig(pkt, offset - OFF_CONFIG);
170 return 0;
171 }
172
173 panic_if(size != 4, "Unexpected write size @ 0x%x: %u\n", offset, size);
174 DPRINTF(VIOIface, " value: 0x%x\n", pkt->getLE<uint32_t>());
175 pkt->makeResponse();
176 write(offset, pkt->getLE<uint32_t>());
177 return 0;
178 }
179
180 void
181 MmioVirtIO::write(Addr offset, uint32_t value)
182 {
183 switch(offset) {
184 case OFF_HOST_FEATURES_SELECT:
185 hostFeaturesSelect = value;
186 return;
187
188 case OFF_GUEST_FEATURES:
189 if (guestFeaturesSelect == 0) {
190 vio.setGuestFeatures(value);
191 } else if (value != 0) {
192 warn("Setting unimplemented guest features register %u: %u\n",
193 guestFeaturesSelect, value);
194 }
195 return;
196
197 case OFF_GUEST_FEATURES_SELECT:
198 guestFeaturesSelect = value;
199 return;
200
201 case OFF_GUEST_PAGE_SIZE:
202 // TODO: We only support 4096 byte pages at the moment
203 panic_if(value != VirtQueue::ALIGN_SIZE,
204 "Unhandled VirtIO page size: %u", value);
205 pageSize = value;
206 return;
207
208 case OFF_QUEUE_SELECT:
209 vio.setQueueSelect(value);
210 return;
211
212 case OFF_QUEUE_NUM:
213 // TODO: We don't support queue resizing, so ignore this for now.
214 warn_once("Ignoring queue resize hint. Requested size: %u\n", value);
215 return;
216
217 case OFF_QUEUE_ALIGN:
218 // TODO: We currently only support the hard-coded 4k alignment used
219 // in legacy VirtIO.
220 panic_if(value != VirtQueue::ALIGN_SIZE,
221 "Unhandled VirtIO alignment size: %u", value);
222 return;
223
224 case OFF_QUEUE_PFN:
225 vio.setQueueAddress(value);
226 return;
227
228 case OFF_QUEUE_NOTIFY:
229 vio.onNotify(value);
230 return;
231
232 case OFF_INTERRUPT_ACK:
233 setInterrupts(interruptStatus & (~value));
234 return;
235
236 case OFF_STATUS:
237 panic_if(value > 0xff, "Unexpected status: 0x%x\n", value);
238 vio.setDeviceStatus(value);
239 return;
240
241 /* Read-only registers */
242 case OFF_MAGIC:
243 case OFF_VERSION:
244 case OFF_DEVICE_ID:
245 case OFF_VENDOR_ID:
246 case OFF_HOST_FEATURES:
247 case OFF_QUEUE_NUM_MAX:
248 case OFF_INTERRUPT_STATUS:
249 warn("Guest is trying to write to read-only register 0x%\n",
250 offset);
251 return;
252
253 default:
254 panic("Unhandled read offset (0x%x)\n", offset);
255 }
256 }
257
258 void
259 MmioVirtIO::kick()
260 {
261 DPRINTF(VIOIface, "kick(): Sending interrupt...\n");
262 setInterrupts(interruptStatus | INT_USED_RING);
263 }
264
265 void
266 MmioVirtIO::setInterrupts(uint32_t value)
267 {
268 const uint32_t old_ints = interruptStatus;
269 interruptStatus = value;
270
271 if (!old_ints && interruptStatus) {
272 interrupt->raise();
273 } else if (old_ints && !interruptStatus) {
274 interrupt->clear();
275 }
276 }
277
278
279 MmioVirtIO *
280 MmioVirtIOParams::create()
281 {
282 return new MmioVirtIO(this);
283 }