vio_mmio.cc revision 13230:2988dc5d1d6f
12567SN/A/*
22567SN/A * Copyright (c) 2016-2018 ARM Limited
32567SN/A * All rights reserved
42567SN/A *
52567SN/A * The license below extends only to copyright in the software and shall
62567SN/A * not be construed as granting a license to any other intellectual
72567SN/A * property including but not limited to intellectual property relating
82567SN/A * to a hardware implementation of the functionality of the software
92567SN/A * licensed hereunder.  You may use the software subject to the license
102567SN/A * terms below provided that you ensure that this notice is replicated
112567SN/A * unmodified and in its entirety in all distributions of the software,
122567SN/A * modified or unmodified, in source code or in binary form.
132567SN/A *
142567SN/A * Redistribution and use in source and binary forms, with or without
152567SN/A * modification, are permitted provided that the following conditions are
162567SN/A * met: redistributions of source code must retain the above copyright
172567SN/A * notice, this list of conditions and the following disclaimer;
182567SN/A * redistributions in binary form must reproduce the above copyright
192567SN/A * notice, this list of conditions and the following disclaimer in the
202567SN/A * documentation and/or other materials provided with the distribution;
212567SN/A * neither the name of the copyright holders nor the names of its
222567SN/A * contributors may be used to endorse or promote products derived from
232567SN/A * this software without specific prior written permission.
242567SN/A *
252567SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
262567SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
272665Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
282665Ssaidi@eecs.umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
292567SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
302567SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
312567SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
322567SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
332567SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
342567SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
352567SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
362567SN/A *
372567SN/A * Authors: Andreas Sandberg
382567SN/A */
392567SN/A
404762Snate@binkert.org#include "dev/arm/vio_mmio.hh"
412567SN/A
422567SN/A#include "debug/VIOIface.hh"
432567SN/A#include "dev/arm/base_gic.hh"
442567SN/A#include "mem/packet_access.hh"
452567SN/A#include "params/MmioVirtIO.hh"
462567SN/A
474762Snate@binkert.orgMmioVirtIO::MmioVirtIO(const MmioVirtIOParams *params)
482567SN/A    : BasicPioDevice(params, params->pio_size),
492650Ssaidi@eecs.umich.edu      hostFeaturesSelect(0), guestFeaturesSelect(0), pageSize(0),
502567SN/A      interruptStatus(0),
518706Sandreas.hansson@arm.com      callbackKick(this), vio(*params->vio),
528706Sandreas.hansson@arm.com      interrupt(params->interrupt->get())
532567SN/A{
542567SN/A    fatal_if(!interrupt, "No MMIO VirtIO interrupt specified\n");
552567SN/A
562567SN/A    vio.registerKickCallback(&callbackKick);
572567SN/A}
582567SN/A
592567SN/AMmioVirtIO::~MmioVirtIO()
602567SN/A{
612567SN/A}
622567SN/A
632567SN/ATick
642567SN/AMmioVirtIO::read(PacketPtr pkt)
652567SN/A{
662567SN/A    const Addr offset = pkt->getAddr() - pioAddr;
672567SN/A    const unsigned size(pkt->getSize());
682567SN/A
693745Sgblack@eecs.umich.edu    DPRINTF(VIOIface, "Reading %u bytes @ 0x%x:\n", size, offset);
703745Sgblack@eecs.umich.edu
713745Sgblack@eecs.umich.edu    // Forward device configuration writes to the device VirtIO model
723745Sgblack@eecs.umich.edu    if (offset >= OFF_CONFIG) {
733745Sgblack@eecs.umich.edu        vio.readConfig(pkt, offset - OFF_CONFIG);
743745Sgblack@eecs.umich.edu        return 0;
753745Sgblack@eecs.umich.edu    }
763745Sgblack@eecs.umich.edu
773745Sgblack@eecs.umich.edu    panic_if(size != 4, "Unexpected read size: %u\n", size);
782567SN/A
792567SN/A    const uint32_t value = read(offset);
802567SN/A    DPRINTF(VIOIface, "    value: 0x%x\n", value);
812567SN/A    pkt->makeResponse();
822567SN/A    pkt->setLE<uint32_t>(value);
832567SN/A
842567SN/A    return 0;
852567SN/A}
862567SN/A
873745Sgblack@eecs.umich.eduuint32_t
883745Sgblack@eecs.umich.eduMmioVirtIO::read(Addr offset)
893745Sgblack@eecs.umich.edu{
903745Sgblack@eecs.umich.edu    switch(offset) {
913745Sgblack@eecs.umich.edu      case OFF_MAGIC:
923745Sgblack@eecs.umich.edu        return MAGIC;
933745Sgblack@eecs.umich.edu
943745Sgblack@eecs.umich.edu      case OFF_VERSION:
953745Sgblack@eecs.umich.edu        return VERSION;
962650Ssaidi@eecs.umich.edu
972650Ssaidi@eecs.umich.edu      case OFF_DEVICE_ID:
982650Ssaidi@eecs.umich.edu        return vio.deviceId;
992567SN/A
1002567SN/A      case OFF_VENDOR_ID:
1012567SN/A        return VENDOR_ID;
1022567SN/A
1032567SN/A      case OFF_HOST_FEATURES:
1047741Sgblack@eecs.umich.edu        // We only implement 32 bits of this register
1057741Sgblack@eecs.umich.edu        if (hostFeaturesSelect == 0)
1062567SN/A            return vio.deviceFeatures;
1072567SN/A        else
1082567SN/A            return 0;
1092567SN/A
1102567SN/A      case OFF_HOST_FEATURES_SELECT:
1112567SN/A        return hostFeaturesSelect;
1127741Sgblack@eecs.umich.edu
1137741Sgblack@eecs.umich.edu      case OFF_GUEST_FEATURES:
1142567SN/A        // We only implement 32 bits of this register
1152567SN/A        if (guestFeaturesSelect == 0)
1162567SN/A            return vio.getGuestFeatures();
1172567SN/A        else
1182567SN/A            return 0;
1192567SN/A
1207741Sgblack@eecs.umich.edu      case OFF_GUEST_FEATURES_SELECT:
1217741Sgblack@eecs.umich.edu        return hostFeaturesSelect;
1222567SN/A
1232567SN/A      case OFF_GUEST_PAGE_SIZE:
1242567SN/A        return pageSize;
1252567SN/A
1267741Sgblack@eecs.umich.edu      case OFF_QUEUE_SELECT:
1277741Sgblack@eecs.umich.edu        return vio.getQueueSelect();
1283553Sgblack@eecs.umich.edu
1293553Sgblack@eecs.umich.edu      case OFF_QUEUE_NUM_MAX:
1303553Sgblack@eecs.umich.edu        return vio.getQueueSize();
1313553Sgblack@eecs.umich.edu
1322567SN/A      case OFF_QUEUE_NUM:
1332567SN/A        // TODO: We don't support queue resizing, so ignore this for now.
1342567SN/A        return vio.getQueueSize();
1352567SN/A
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->getLE<uint32_t>());
177    pkt->makeResponse();
178    write(offset, pkt->getLE<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