vio_mmio.cc revision 12974
15217Ssaidi@eecs.umich.edu/*
25217Ssaidi@eecs.umich.edu * Copyright (c) 2016-2018 ARM Limited
35217Ssaidi@eecs.umich.edu * All rights reserved
45217Ssaidi@eecs.umich.edu *
55217Ssaidi@eecs.umich.edu * The license below extends only to copyright in the software and shall
65217Ssaidi@eecs.umich.edu * not be construed as granting a license to any other intellectual
75217Ssaidi@eecs.umich.edu * property including but not limited to intellectual property relating
85217Ssaidi@eecs.umich.edu * to a hardware implementation of the functionality of the software
95217Ssaidi@eecs.umich.edu * licensed hereunder.  You may use the software subject to the license
105217Ssaidi@eecs.umich.edu * terms below provided that you ensure that this notice is replicated
115217Ssaidi@eecs.umich.edu * unmodified and in its entirety in all distributions of the software,
125217Ssaidi@eecs.umich.edu * modified or unmodified, in source code or in binary form.
135217Ssaidi@eecs.umich.edu *
145217Ssaidi@eecs.umich.edu * Redistribution and use in source and binary forms, with or without
155217Ssaidi@eecs.umich.edu * modification, are permitted provided that the following conditions are
165217Ssaidi@eecs.umich.edu * met: redistributions of source code must retain the above copyright
175217Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer;
185217Ssaidi@eecs.umich.edu * redistributions in binary form must reproduce the above copyright
195217Ssaidi@eecs.umich.edu * notice, this list of conditions and the following disclaimer in the
205217Ssaidi@eecs.umich.edu * documentation and/or other materials provided with the distribution;
215217Ssaidi@eecs.umich.edu * neither the name of the copyright holders nor the names of its
225217Ssaidi@eecs.umich.edu * contributors may be used to endorse or promote products derived from
235217Ssaidi@eecs.umich.edu * this software without specific prior written permission.
245217Ssaidi@eecs.umich.edu *
255217Ssaidi@eecs.umich.edu * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
265217Ssaidi@eecs.umich.edu * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
275217Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
285217Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
295217Ssaidi@eecs.umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
305217Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
315217Ssaidi@eecs.umich.edu * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
325217Ssaidi@eecs.umich.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
336658Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
345217Ssaidi@eecs.umich.edu * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
355217Ssaidi@eecs.umich.edu * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
365217Ssaidi@eecs.umich.edu *
375217Ssaidi@eecs.umich.edu * Authors: Andreas Sandberg
385217Ssaidi@eecs.umich.edu */
395217Ssaidi@eecs.umich.edu
405217Ssaidi@eecs.umich.edu#include "dev/arm/vio_mmio.hh"
415217Ssaidi@eecs.umich.edu
425217Ssaidi@eecs.umich.edu#include "debug/VIOIface.hh"
435217Ssaidi@eecs.umich.edu#include "dev/arm/base_gic.hh"
445217Ssaidi@eecs.umich.edu#include "mem/packet_access.hh"
455217Ssaidi@eecs.umich.edu#include "params/MmioVirtIO.hh"
465217Ssaidi@eecs.umich.edu
475217Ssaidi@eecs.umich.eduMmioVirtIO::MmioVirtIO(const MmioVirtIOParams *params)
485217Ssaidi@eecs.umich.edu    : BasicPioDevice(params, params->pio_size),
495217Ssaidi@eecs.umich.edu      hostFeaturesSelect(0), guestFeaturesSelect(0), pageSize(0),
505217Ssaidi@eecs.umich.edu      interruptStatus(0),
515217Ssaidi@eecs.umich.edu      callbackKick(this), vio(*params->vio),
525217Ssaidi@eecs.umich.edu      interrupt(params->interrupt->get())
535217Ssaidi@eecs.umich.edu{
545217Ssaidi@eecs.umich.edu    fatal_if(!interrupt, "No MMIO VirtIO interrupt specified\n");
555217Ssaidi@eecs.umich.edu
565217Ssaidi@eecs.umich.edu    vio.registerKickCallback(&callbackKick);
575217Ssaidi@eecs.umich.edu}
585217Ssaidi@eecs.umich.edu
595217Ssaidi@eecs.umich.eduMmioVirtIO::~MmioVirtIO()
605217Ssaidi@eecs.umich.edu{
615217Ssaidi@eecs.umich.edu}
625217Ssaidi@eecs.umich.edu
635217Ssaidi@eecs.umich.eduTick
645217Ssaidi@eecs.umich.eduMmioVirtIO::read(PacketPtr pkt)
655217Ssaidi@eecs.umich.edu{
665217Ssaidi@eecs.umich.edu    const Addr offset = pkt->getAddr() - pioAddr;
675217Ssaidi@eecs.umich.edu    const unsigned size(pkt->getSize());
687720Sgblack@eecs.umich.edu
697720Sgblack@eecs.umich.edu    DPRINTF(VIOIface, "Reading %u bytes @ 0x%x:\n", size, offset);
705712Shsul@eecs.umich.edu
715712Shsul@eecs.umich.edu    // Forward device configuration writes to the device VirtIO model
725217Ssaidi@eecs.umich.edu    if (offset >= OFF_CONFIG) {
735217Ssaidi@eecs.umich.edu        vio.readConfig(pkt, offset - OFF_CONFIG);
745714Shsul@eecs.umich.edu        return 0;
755714Shsul@eecs.umich.edu    }
765714Shsul@eecs.umich.edu
775714Shsul@eecs.umich.edu    panic_if(size != 4, "Unexpected read size: %u\n", size);
785714Shsul@eecs.umich.edu
795714Shsul@eecs.umich.edu    const uint32_t value = read(offset);
805714Shsul@eecs.umich.edu    DPRINTF(VIOIface, "    value: 0x%x\n", value);
815217Ssaidi@eecs.umich.edu    pkt->makeResponse();
82    pkt->set<uint32_t>(value);
83
84    return 0;
85}
86
87uint32_t
88MmioVirtIO::read(Addr offset)
89{
90    switch(offset) {
91      case OFF_MAGIC:
92        return MAGIC;
93
94      case OFF_VERSION:
95        return VERSION;
96
97      case OFF_DEVICE_ID:
98        return vio.deviceId;
99
100      case OFF_VENDOR_ID:
101        return VENDOR_ID;
102
103      case OFF_HOST_FEATURES:
104        // We only implement 32 bits of this register
105        if (hostFeaturesSelect == 0)
106            return vio.deviceFeatures;
107        else
108            return 0;
109
110      case OFF_HOST_FEATURES_SELECT:
111        return hostFeaturesSelect;
112
113      case OFF_GUEST_FEATURES:
114        // We only implement 32 bits of this register
115        if (guestFeaturesSelect == 0)
116            return vio.getGuestFeatures();
117        else
118            return 0;
119
120      case OFF_GUEST_FEATURES_SELECT:
121        return hostFeaturesSelect;
122
123      case OFF_GUEST_PAGE_SIZE:
124        return pageSize;
125
126      case OFF_QUEUE_SELECT:
127        return vio.getQueueSelect();
128
129      case OFF_QUEUE_NUM_MAX:
130        return vio.getQueueSize();
131
132      case OFF_QUEUE_NUM:
133        // TODO: We don't support queue resizing, so ignore this for now.
134        return vio.getQueueSize();
135
136      case OFF_QUEUE_ALIGN:
137        // TODO: Implement this once we support other alignment sizes
138        return VirtQueue::ALIGN_SIZE;
139
140      case OFF_QUEUE_PFN:
141        return vio.getQueueAddress();
142
143      case OFF_INTERRUPT_STATUS:
144        return interruptStatus;
145
146      case OFF_STATUS:
147        return vio.getDeviceStatus();
148
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",
153             offset);
154        return 0;
155
156      default:
157        panic("Unhandled read offset (0x%x)\n", offset);
158    }
159}
160
161Tick
162MmioVirtIO::write(PacketPtr pkt)
163{
164    const Addr offset = pkt->getAddr() - pioAddr;
165    const unsigned size(pkt->getSize());
166
167    DPRINTF(VIOIface, "Writing %u bytes @ 0x%x:\n", size, offset);
168
169    // Forward device configuration writes to the device VirtIO model
170    if (offset >= OFF_CONFIG) {
171        vio.writeConfig(pkt, offset - OFF_CONFIG);
172        return 0;
173    }
174
175    panic_if(size != 4, "Unexpected write size @ 0x%x: %u\n", offset, size);
176    DPRINTF(VIOIface, "    value: 0x%x\n", pkt->get<uint32_t>());
177    pkt->makeResponse();
178    write(offset, pkt->get<uint32_t>());
179    return 0;
180}
181
182void
183MmioVirtIO::write(Addr offset, uint32_t value)
184{
185    switch(offset) {
186      case OFF_HOST_FEATURES_SELECT:
187        hostFeaturesSelect = value;
188        return;
189
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);
196        }
197        return;
198
199      case OFF_GUEST_FEATURES_SELECT:
200        guestFeaturesSelect = value;
201        return;
202
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);
207        pageSize = value;
208        return;
209
210      case OFF_QUEUE_SELECT:
211        vio.setQueueSelect(value);
212        return;
213
214      case OFF_QUEUE_NUM:
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);
217        return;
218
219      case OFF_QUEUE_ALIGN:
220        // TODO: We currently only support the hard-coded 4k alignment used
221        // in legacy VirtIO.
222        panic_if(value != VirtQueue::ALIGN_SIZE,
223                 "Unhandled VirtIO alignment size: %u", value);
224        return;
225
226      case OFF_QUEUE_PFN:
227        vio.setQueueAddress(value);
228        return;
229
230      case OFF_QUEUE_NOTIFY:
231        vio.onNotify(value);
232        return;
233
234      case OFF_INTERRUPT_ACK:
235        setInterrupts(interruptStatus & (~value));
236        return;
237
238      case OFF_STATUS:
239        panic_if(value > 0xff, "Unexpected status: 0x%x\n", value);
240        vio.setDeviceStatus(value);
241        return;
242
243        /* Read-only registers */
244      case OFF_MAGIC:
245      case OFF_VERSION:
246      case OFF_DEVICE_ID:
247      case OFF_VENDOR_ID:
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",
252             offset);
253        return;
254
255      default:
256        panic("Unhandled read offset (0x%x)\n", offset);
257    }
258}
259
260void
261MmioVirtIO::kick()
262{
263    DPRINTF(VIOIface, "kick(): Sending interrupt...\n");
264    setInterrupts(interruptStatus | INT_USED_RING);
265}
266
267void
268MmioVirtIO::setInterrupts(uint32_t value)
269{
270    const uint32_t old_ints = interruptStatus;
271    interruptStatus = value;
272
273    if (!old_ints && interruptStatus) {
274        interrupt->raise();
275    } else if (old_ints && !interruptStatus) {
276        interrupt->clear();
277    }
278}
279
280
281MmioVirtIO *
282MmioVirtIOParams::create()
283{
284    return new MmioVirtIO(this);
285}
286