vio_mmio.cc revision 12740
112740Sandreas.sandberg@arm.com/*
212740Sandreas.sandberg@arm.com * Copyright (c) 2016-2018 ARM Limited
312740Sandreas.sandberg@arm.com * All rights reserved
412740Sandreas.sandberg@arm.com *
512740Sandreas.sandberg@arm.com * The license below extends only to copyright in the software and shall
612740Sandreas.sandberg@arm.com * not be construed as granting a license to any other intellectual
712740Sandreas.sandberg@arm.com * property including but not limited to intellectual property relating
812740Sandreas.sandberg@arm.com * to a hardware implementation of the functionality of the software
912740Sandreas.sandberg@arm.com * licensed hereunder.  You may use the software subject to the license
1012740Sandreas.sandberg@arm.com * terms below provided that you ensure that this notice is replicated
1112740Sandreas.sandberg@arm.com * unmodified and in its entirety in all distributions of the software,
1212740Sandreas.sandberg@arm.com * modified or unmodified, in source code or in binary form.
1312740Sandreas.sandberg@arm.com *
1412740Sandreas.sandberg@arm.com * Redistribution and use in source and binary forms, with or without
1512740Sandreas.sandberg@arm.com * modification, are permitted provided that the following conditions are
1612740Sandreas.sandberg@arm.com * met: redistributions of source code must retain the above copyright
1712740Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer;
1812740Sandreas.sandberg@arm.com * redistributions in binary form must reproduce the above copyright
1912740Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer in the
2012740Sandreas.sandberg@arm.com * documentation and/or other materials provided with the distribution;
2112740Sandreas.sandberg@arm.com * neither the name of the copyright holders nor the names of its
2212740Sandreas.sandberg@arm.com * contributors may be used to endorse or promote products derived from
2312740Sandreas.sandberg@arm.com * this software without specific prior written permission.
2412740Sandreas.sandberg@arm.com *
2512740Sandreas.sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2612740Sandreas.sandberg@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2712740Sandreas.sandberg@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2812740Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2912740Sandreas.sandberg@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3012740Sandreas.sandberg@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3112740Sandreas.sandberg@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3212740Sandreas.sandberg@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3312740Sandreas.sandberg@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3412740Sandreas.sandberg@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3512740Sandreas.sandberg@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3612740Sandreas.sandberg@arm.com *
3712740Sandreas.sandberg@arm.com * Authors: Andreas Sandberg
3812740Sandreas.sandberg@arm.com */
3912740Sandreas.sandberg@arm.com
4012740Sandreas.sandberg@arm.com#include "dev/arm/vio_mmio.hh"
4112740Sandreas.sandberg@arm.com
4212740Sandreas.sandberg@arm.com#include "debug/VIOIface.hh"
4312740Sandreas.sandberg@arm.com#include "dev/arm/base_gic.hh"
4412740Sandreas.sandberg@arm.com#include "mem/packet_access.hh"
4512740Sandreas.sandberg@arm.com#include "params/MmioVirtIO.hh"
4612740Sandreas.sandberg@arm.com
4712740Sandreas.sandberg@arm.comMmioVirtIO::MmioVirtIO(const MmioVirtIOParams *params)
4812740Sandreas.sandberg@arm.com    : BasicPioDevice(params, params->pio_size),
4912740Sandreas.sandberg@arm.com      hostFeaturesSelect(0), guestFeaturesSelect(0), pageSize(0),
5012740Sandreas.sandberg@arm.com      interruptStatus(0),
5112740Sandreas.sandberg@arm.com      callbackKick(this), vio(*params->vio), interrupt(params->interrupt)
5212740Sandreas.sandberg@arm.com{
5312740Sandreas.sandberg@arm.com    fatal_if(!interrupt, "No MMIO VirtIO interrupt specified\n");
5412740Sandreas.sandberg@arm.com
5512740Sandreas.sandberg@arm.com    vio.registerKickCallback(&callbackKick);
5612740Sandreas.sandberg@arm.com}
5712740Sandreas.sandberg@arm.com
5812740Sandreas.sandberg@arm.comMmioVirtIO::~MmioVirtIO()
5912740Sandreas.sandberg@arm.com{
6012740Sandreas.sandberg@arm.com}
6112740Sandreas.sandberg@arm.com
6212740Sandreas.sandberg@arm.comTick
6312740Sandreas.sandberg@arm.comMmioVirtIO::read(PacketPtr pkt)
6412740Sandreas.sandberg@arm.com{
6512740Sandreas.sandberg@arm.com    const Addr offset = pkt->getAddr() - pioAddr;
6612740Sandreas.sandberg@arm.com    const unsigned size(pkt->getSize());
6712740Sandreas.sandberg@arm.com
6812740Sandreas.sandberg@arm.com    DPRINTF(VIOIface, "Reading %u bytes @ 0x%x:\n", size, offset);
6912740Sandreas.sandberg@arm.com
7012740Sandreas.sandberg@arm.com    // Forward device configuration writes to the device VirtIO model
7112740Sandreas.sandberg@arm.com    if (offset >= OFF_CONFIG) {
7212740Sandreas.sandberg@arm.com        vio.readConfig(pkt, offset - OFF_CONFIG);
7312740Sandreas.sandberg@arm.com        return 0;
7412740Sandreas.sandberg@arm.com    }
7512740Sandreas.sandberg@arm.com
7612740Sandreas.sandberg@arm.com    panic_if(size != 4, "Unexpected read size: %u\n", size);
7712740Sandreas.sandberg@arm.com
7812740Sandreas.sandberg@arm.com    const uint32_t value = read(offset);
7912740Sandreas.sandberg@arm.com    DPRINTF(VIOIface, "    value: 0x%x\n", value);
8012740Sandreas.sandberg@arm.com    pkt->makeResponse();
8112740Sandreas.sandberg@arm.com    pkt->set<uint32_t>(value);
8212740Sandreas.sandberg@arm.com
8312740Sandreas.sandberg@arm.com    return 0;
8412740Sandreas.sandberg@arm.com}
8512740Sandreas.sandberg@arm.com
8612740Sandreas.sandberg@arm.comuint32_t
8712740Sandreas.sandberg@arm.comMmioVirtIO::read(Addr offset)
8812740Sandreas.sandberg@arm.com{
8912740Sandreas.sandberg@arm.com    switch(offset) {
9012740Sandreas.sandberg@arm.com      case OFF_MAGIC:
9112740Sandreas.sandberg@arm.com        return MAGIC;
9212740Sandreas.sandberg@arm.com
9312740Sandreas.sandberg@arm.com      case OFF_VERSION:
9412740Sandreas.sandberg@arm.com        return VERSION;
9512740Sandreas.sandberg@arm.com
9612740Sandreas.sandberg@arm.com      case OFF_DEVICE_ID:
9712740Sandreas.sandberg@arm.com        return vio.deviceId;
9812740Sandreas.sandberg@arm.com
9912740Sandreas.sandberg@arm.com      case OFF_VENDOR_ID:
10012740Sandreas.sandberg@arm.com        return VENDOR_ID;
10112740Sandreas.sandberg@arm.com
10212740Sandreas.sandberg@arm.com      case OFF_HOST_FEATURES:
10312740Sandreas.sandberg@arm.com        // We only implement 32 bits of this register
10412740Sandreas.sandberg@arm.com        if (hostFeaturesSelect == 0)
10512740Sandreas.sandberg@arm.com            return vio.deviceFeatures;
10612740Sandreas.sandberg@arm.com        else
10712740Sandreas.sandberg@arm.com            return 0;
10812740Sandreas.sandberg@arm.com
10912740Sandreas.sandberg@arm.com      case OFF_HOST_FEATURES_SELECT:
11012740Sandreas.sandberg@arm.com        return hostFeaturesSelect;
11112740Sandreas.sandberg@arm.com
11212740Sandreas.sandberg@arm.com      case OFF_GUEST_FEATURES:
11312740Sandreas.sandberg@arm.com        // We only implement 32 bits of this register
11412740Sandreas.sandberg@arm.com        if (guestFeaturesSelect == 0)
11512740Sandreas.sandberg@arm.com            return vio.getGuestFeatures();
11612740Sandreas.sandberg@arm.com        else
11712740Sandreas.sandberg@arm.com            return 0;
11812740Sandreas.sandberg@arm.com
11912740Sandreas.sandberg@arm.com      case OFF_GUEST_FEATURES_SELECT:
12012740Sandreas.sandberg@arm.com        return hostFeaturesSelect;
12112740Sandreas.sandberg@arm.com
12212740Sandreas.sandberg@arm.com      case OFF_GUEST_PAGE_SIZE:
12312740Sandreas.sandberg@arm.com        return pageSize;
12412740Sandreas.sandberg@arm.com
12512740Sandreas.sandberg@arm.com      case OFF_QUEUE_SELECT:
12612740Sandreas.sandberg@arm.com        return vio.getQueueSelect();
12712740Sandreas.sandberg@arm.com
12812740Sandreas.sandberg@arm.com      case OFF_QUEUE_NUM_MAX:
12912740Sandreas.sandberg@arm.com        return vio.getQueueSize();
13012740Sandreas.sandberg@arm.com
13112740Sandreas.sandberg@arm.com      case OFF_QUEUE_NUM:
13212740Sandreas.sandberg@arm.com        // TODO: We don't support queue resizing, so ignore this for now.
13312740Sandreas.sandberg@arm.com        return vio.getQueueSize();
13412740Sandreas.sandberg@arm.com
13512740Sandreas.sandberg@arm.com      case OFF_QUEUE_ALIGN:
13612740Sandreas.sandberg@arm.com        // TODO: Implement this once we support other alignment sizes
13712740Sandreas.sandberg@arm.com        return VirtQueue::ALIGN_SIZE;
13812740Sandreas.sandberg@arm.com
13912740Sandreas.sandberg@arm.com      case OFF_QUEUE_PFN:
14012740Sandreas.sandberg@arm.com        return vio.getQueueAddress();
14112740Sandreas.sandberg@arm.com
14212740Sandreas.sandberg@arm.com      case OFF_INTERRUPT_STATUS:
14312740Sandreas.sandberg@arm.com        return interruptStatus;
14412740Sandreas.sandberg@arm.com
14512740Sandreas.sandberg@arm.com      case OFF_STATUS:
14612740Sandreas.sandberg@arm.com        return vio.getDeviceStatus();
14712740Sandreas.sandberg@arm.com
14812740Sandreas.sandberg@arm.com        // Write-only registers
14912740Sandreas.sandberg@arm.com      case OFF_QUEUE_NOTIFY:
15012740Sandreas.sandberg@arm.com      case OFF_INTERRUPT_ACK:
15112740Sandreas.sandberg@arm.com        warn("Guest is trying to read to write-only register 0x%\n",
15212740Sandreas.sandberg@arm.com             offset);
15312740Sandreas.sandberg@arm.com        return 0;
15412740Sandreas.sandberg@arm.com
15512740Sandreas.sandberg@arm.com      default:
15612740Sandreas.sandberg@arm.com        panic("Unhandled read offset (0x%x)\n", offset);
15712740Sandreas.sandberg@arm.com    }
15812740Sandreas.sandberg@arm.com}
15912740Sandreas.sandberg@arm.com
16012740Sandreas.sandberg@arm.comTick
16112740Sandreas.sandberg@arm.comMmioVirtIO::write(PacketPtr pkt)
16212740Sandreas.sandberg@arm.com{
16312740Sandreas.sandberg@arm.com    const Addr offset = pkt->getAddr() - pioAddr;
16412740Sandreas.sandberg@arm.com    const unsigned size(pkt->getSize());
16512740Sandreas.sandberg@arm.com
16612740Sandreas.sandberg@arm.com    DPRINTF(VIOIface, "Writing %u bytes @ 0x%x:\n", size, offset);
16712740Sandreas.sandberg@arm.com
16812740Sandreas.sandberg@arm.com    // Forward device configuration writes to the device VirtIO model
16912740Sandreas.sandberg@arm.com    if (offset >= OFF_CONFIG) {
17012740Sandreas.sandberg@arm.com        vio.writeConfig(pkt, offset - OFF_CONFIG);
17112740Sandreas.sandberg@arm.com        return 0;
17212740Sandreas.sandberg@arm.com    }
17312740Sandreas.sandberg@arm.com
17412740Sandreas.sandberg@arm.com    panic_if(size != 4, "Unexpected write size @ 0x%x: %u\n", offset, size);
17512740Sandreas.sandberg@arm.com    DPRINTF(VIOIface, "    value: 0x%x\n", pkt->get<uint32_t>());
17612740Sandreas.sandberg@arm.com    pkt->makeResponse();
17712740Sandreas.sandberg@arm.com    write(offset, pkt->get<uint32_t>());
17812740Sandreas.sandberg@arm.com    return 0;
17912740Sandreas.sandberg@arm.com}
18012740Sandreas.sandberg@arm.com
18112740Sandreas.sandberg@arm.comvoid
18212740Sandreas.sandberg@arm.comMmioVirtIO::write(Addr offset, uint32_t value)
18312740Sandreas.sandberg@arm.com{
18412740Sandreas.sandberg@arm.com    switch(offset) {
18512740Sandreas.sandberg@arm.com      case OFF_HOST_FEATURES_SELECT:
18612740Sandreas.sandberg@arm.com        hostFeaturesSelect = value;
18712740Sandreas.sandberg@arm.com        return;
18812740Sandreas.sandberg@arm.com
18912740Sandreas.sandberg@arm.com      case OFF_GUEST_FEATURES:
19012740Sandreas.sandberg@arm.com        if (guestFeaturesSelect == 0) {
19112740Sandreas.sandberg@arm.com            vio.setGuestFeatures(value);
19212740Sandreas.sandberg@arm.com        } else if (value != 0) {
19312740Sandreas.sandberg@arm.com            warn("Setting unimplemented guest features register %u: %u\n",
19412740Sandreas.sandberg@arm.com                 guestFeaturesSelect, value);
19512740Sandreas.sandberg@arm.com        }
19612740Sandreas.sandberg@arm.com        return;
19712740Sandreas.sandberg@arm.com
19812740Sandreas.sandberg@arm.com      case OFF_GUEST_FEATURES_SELECT:
19912740Sandreas.sandberg@arm.com        guestFeaturesSelect = value;
20012740Sandreas.sandberg@arm.com        return;
20112740Sandreas.sandberg@arm.com
20212740Sandreas.sandberg@arm.com      case OFF_GUEST_PAGE_SIZE:
20312740Sandreas.sandberg@arm.com        // TODO: We only support 4096 byte pages at the moment
20412740Sandreas.sandberg@arm.com        panic_if(value != VirtQueue::ALIGN_SIZE,
20512740Sandreas.sandberg@arm.com                 "Unhandled VirtIO page size: %u", value);
20612740Sandreas.sandberg@arm.com        pageSize = value;
20712740Sandreas.sandberg@arm.com        return;
20812740Sandreas.sandberg@arm.com
20912740Sandreas.sandberg@arm.com      case OFF_QUEUE_SELECT:
21012740Sandreas.sandberg@arm.com        vio.setQueueSelect(value);
21112740Sandreas.sandberg@arm.com        return;
21212740Sandreas.sandberg@arm.com
21312740Sandreas.sandberg@arm.com      case OFF_QUEUE_NUM:
21412740Sandreas.sandberg@arm.com        // TODO: We don't support queue resizing, so ignore this for now.
21512740Sandreas.sandberg@arm.com        warn_once("Ignoring queue resize hint. Requested size: %u\n", value);
21612740Sandreas.sandberg@arm.com        return;
21712740Sandreas.sandberg@arm.com
21812740Sandreas.sandberg@arm.com      case OFF_QUEUE_ALIGN:
21912740Sandreas.sandberg@arm.com        // TODO: We currently only support the hard-coded 4k alignment used
22012740Sandreas.sandberg@arm.com        // in legacy VirtIO.
22112740Sandreas.sandberg@arm.com        panic_if(value != VirtQueue::ALIGN_SIZE,
22212740Sandreas.sandberg@arm.com                 "Unhandled VirtIO alignment size: %u", value);
22312740Sandreas.sandberg@arm.com        return;
22412740Sandreas.sandberg@arm.com
22512740Sandreas.sandberg@arm.com      case OFF_QUEUE_PFN:
22612740Sandreas.sandberg@arm.com        vio.setQueueAddress(value);
22712740Sandreas.sandberg@arm.com        return;
22812740Sandreas.sandberg@arm.com
22912740Sandreas.sandberg@arm.com      case OFF_QUEUE_NOTIFY:
23012740Sandreas.sandberg@arm.com        vio.onNotify(value);
23112740Sandreas.sandberg@arm.com        return;
23212740Sandreas.sandberg@arm.com
23312740Sandreas.sandberg@arm.com      case OFF_INTERRUPT_ACK:
23412740Sandreas.sandberg@arm.com        setInterrupts(interruptStatus & (~value));
23512740Sandreas.sandberg@arm.com        return;
23612740Sandreas.sandberg@arm.com
23712740Sandreas.sandberg@arm.com      case OFF_STATUS:
23812740Sandreas.sandberg@arm.com        panic_if(value > 0xff, "Unexpected status: 0x%x\n", value);
23912740Sandreas.sandberg@arm.com        vio.setDeviceStatus(value);
24012740Sandreas.sandberg@arm.com        return;
24112740Sandreas.sandberg@arm.com
24212740Sandreas.sandberg@arm.com        /* Read-only registers */
24312740Sandreas.sandberg@arm.com      case OFF_MAGIC:
24412740Sandreas.sandberg@arm.com      case OFF_VERSION:
24512740Sandreas.sandberg@arm.com      case OFF_DEVICE_ID:
24612740Sandreas.sandberg@arm.com      case OFF_VENDOR_ID:
24712740Sandreas.sandberg@arm.com      case OFF_HOST_FEATURES:
24812740Sandreas.sandberg@arm.com      case OFF_QUEUE_NUM_MAX:
24912740Sandreas.sandberg@arm.com      case OFF_INTERRUPT_STATUS:
25012740Sandreas.sandberg@arm.com        warn("Guest is trying to write to read-only register 0x%\n",
25112740Sandreas.sandberg@arm.com             offset);
25212740Sandreas.sandberg@arm.com        return;
25312740Sandreas.sandberg@arm.com
25412740Sandreas.sandberg@arm.com      default:
25512740Sandreas.sandberg@arm.com        panic("Unhandled read offset (0x%x)\n", offset);
25612740Sandreas.sandberg@arm.com    }
25712740Sandreas.sandberg@arm.com}
25812740Sandreas.sandberg@arm.com
25912740Sandreas.sandberg@arm.comvoid
26012740Sandreas.sandberg@arm.comMmioVirtIO::kick()
26112740Sandreas.sandberg@arm.com{
26212740Sandreas.sandberg@arm.com    DPRINTF(VIOIface, "kick(): Sending interrupt...\n");
26312740Sandreas.sandberg@arm.com    setInterrupts(interruptStatus | INT_USED_RING);
26412740Sandreas.sandberg@arm.com}
26512740Sandreas.sandberg@arm.com
26612740Sandreas.sandberg@arm.comvoid
26712740Sandreas.sandberg@arm.comMmioVirtIO::setInterrupts(uint32_t value)
26812740Sandreas.sandberg@arm.com{
26912740Sandreas.sandberg@arm.com    const uint32_t old_ints = interruptStatus;
27012740Sandreas.sandberg@arm.com    interruptStatus = value;
27112740Sandreas.sandberg@arm.com
27212740Sandreas.sandberg@arm.com    if (!old_ints && interruptStatus) {
27312740Sandreas.sandberg@arm.com        interrupt->raise();
27412740Sandreas.sandberg@arm.com    } else if (old_ints && !interruptStatus) {
27512740Sandreas.sandberg@arm.com        interrupt->clear();
27612740Sandreas.sandberg@arm.com    }
27712740Sandreas.sandberg@arm.com}
27812740Sandreas.sandberg@arm.com
27912740Sandreas.sandberg@arm.com
28012740Sandreas.sandberg@arm.comMmioVirtIO *
28112740Sandreas.sandberg@arm.comMmioVirtIOParams::create()
28212740Sandreas.sandberg@arm.com{
28312740Sandreas.sandberg@arm.com    return new MmioVirtIO(this);
28412740Sandreas.sandberg@arm.com}
285