2 * Copyright (c) 2016-2018 ARM Limited
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.
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.
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.
37 * Authors: Andreas Sandberg
40 #include "dev/arm/vio_mmio.hh"
42 #include "debug/VIOIface.hh"
43 #include "dev/arm/base_gic.hh"
44 #include "mem/packet_access.hh"
45 #include "params/MmioVirtIO.hh"
47 MmioVirtIO::MmioVirtIO(const MmioVirtIOParams
*params
)
48 : BasicPioDevice(params
, params
->pio_size
),
49 hostFeaturesSelect(0), guestFeaturesSelect(0), pageSize(0),
51 callbackKick(this), vio(*params
->vio
),
52 interrupt(params
->interrupt
->get())
54 fatal_if(!interrupt
, "No MMIO VirtIO interrupt specified\n");
56 vio
.registerKickCallback(&callbackKick
);
59 MmioVirtIO::~MmioVirtIO()
64 MmioVirtIO::read(PacketPtr pkt
)
66 const Addr offset
= pkt
->getAddr() - pioAddr
;
67 const unsigned size(pkt
->getSize());
69 DPRINTF(VIOIface
, "Reading %u bytes @ 0x%x:\n", size
, offset
);
71 // Forward device configuration writes to the device VirtIO model
72 if (offset
>= OFF_CONFIG
) {
73 vio
.readConfig(pkt
, offset
- OFF_CONFIG
);
77 panic_if(size
!= 4, "Unexpected read size: %u\n", size
);
79 const uint32_t value
= read(offset
);
80 DPRINTF(VIOIface
, " value: 0x%x\n", value
);
82 pkt
->setLE
<uint32_t>(value
);
88 MmioVirtIO::read(Addr offset
)
103 case OFF_HOST_FEATURES
:
104 // We only implement 32 bits of this register
105 if (hostFeaturesSelect
== 0)
106 return vio
.deviceFeatures
;
110 case OFF_HOST_FEATURES_SELECT
:
111 return hostFeaturesSelect
;
113 case OFF_GUEST_FEATURES
:
114 // We only implement 32 bits of this register
115 if (guestFeaturesSelect
== 0)
116 return vio
.getGuestFeatures();
120 case OFF_GUEST_FEATURES_SELECT
:
121 return hostFeaturesSelect
;
123 case OFF_GUEST_PAGE_SIZE
:
126 case OFF_QUEUE_SELECT
:
127 return vio
.getQueueSelect();
129 case OFF_QUEUE_NUM_MAX
:
130 return vio
.getQueueSize();
133 // TODO: We don't support queue resizing, so ignore this for now.
134 return vio
.getQueueSize();
136 case OFF_QUEUE_ALIGN
:
137 // TODO: Implement this once we support other alignment sizes
138 return VirtQueue::ALIGN_SIZE
;
141 return vio
.getQueueAddress();
143 case OFF_INTERRUPT_STATUS
:
144 return interruptStatus
;
147 return vio
.getDeviceStatus();
149 // Write-only registers
150 case OFF_QUEUE_NOTIFY
:
151 case OFF_INTERRUPT_ACK
:
152 warn("Guest is trying to read to write-only register 0x%\n",
157 panic("Unhandled read offset (0x%x)\n", offset
);
162 MmioVirtIO::write(PacketPtr pkt
)
164 const Addr offset
= pkt
->getAddr() - pioAddr
;
165 const unsigned size(pkt
->getSize());
167 DPRINTF(VIOIface
, "Writing %u bytes @ 0x%x:\n", size
, offset
);
169 // Forward device configuration writes to the device VirtIO model
170 if (offset
>= OFF_CONFIG
) {
171 vio
.writeConfig(pkt
, offset
- OFF_CONFIG
);
175 panic_if(size
!= 4, "Unexpected write size @ 0x%x: %u\n", offset
, size
);
176 DPRINTF(VIOIface
, " value: 0x%x\n", pkt
->getLE
<uint32_t>());
178 write(offset
, pkt
->getLE
<uint32_t>());
183 MmioVirtIO::write(Addr offset
, uint32_t value
)
186 case OFF_HOST_FEATURES_SELECT
:
187 hostFeaturesSelect
= value
;
190 case OFF_GUEST_FEATURES
:
191 if (guestFeaturesSelect
== 0) {
192 vio
.setGuestFeatures(value
);
193 } else if (value
!= 0) {
194 warn("Setting unimplemented guest features register %u: %u\n",
195 guestFeaturesSelect
, value
);
199 case OFF_GUEST_FEATURES_SELECT
:
200 guestFeaturesSelect
= value
;
203 case OFF_GUEST_PAGE_SIZE
:
204 // TODO: We only support 4096 byte pages at the moment
205 panic_if(value
!= VirtQueue::ALIGN_SIZE
,
206 "Unhandled VirtIO page size: %u", value
);
210 case OFF_QUEUE_SELECT
:
211 vio
.setQueueSelect(value
);
215 // TODO: We don't support queue resizing, so ignore this for now.
216 warn_once("Ignoring queue resize hint. Requested size: %u\n", value
);
219 case OFF_QUEUE_ALIGN
:
220 // TODO: We currently only support the hard-coded 4k alignment used
222 panic_if(value
!= VirtQueue::ALIGN_SIZE
,
223 "Unhandled VirtIO alignment size: %u", value
);
227 vio
.setQueueAddress(value
);
230 case OFF_QUEUE_NOTIFY
:
234 case OFF_INTERRUPT_ACK
:
235 setInterrupts(interruptStatus
& (~value
));
239 panic_if(value
> 0xff, "Unexpected status: 0x%x\n", value
);
240 vio
.setDeviceStatus(value
);
243 /* Read-only registers */
248 case OFF_HOST_FEATURES
:
249 case OFF_QUEUE_NUM_MAX
:
250 case OFF_INTERRUPT_STATUS
:
251 warn("Guest is trying to write to read-only register 0x%\n",
256 panic("Unhandled read offset (0x%x)\n", offset
);
263 DPRINTF(VIOIface
, "kick(): Sending interrupt...\n");
264 setInterrupts(interruptStatus
| INT_USED_RING
);
268 MmioVirtIO::setInterrupts(uint32_t value
)
270 const uint32_t old_ints
= interruptStatus
;
271 interruptStatus
= value
;
273 if (!old_ints
&& interruptStatus
) {
275 } else if (old_ints
&& !interruptStatus
) {
282 MmioVirtIOParams::create()
284 return new MmioVirtIO(this);