pci.cc revision 10388:a26a20060ba3
112855Sgabeblack@google.com/*
212855Sgabeblack@google.com * Copyright (c) 2014 ARM Limited
312855Sgabeblack@google.com * All rights reserved
412855Sgabeblack@google.com *
512855Sgabeblack@google.com * The license below extends only to copyright in the software and shall
612855Sgabeblack@google.com * not be construed as granting a license to any other intellectual
712855Sgabeblack@google.com * property including but not limited to intellectual property relating
812855Sgabeblack@google.com * to a hardware implementation of the functionality of the software
912855Sgabeblack@google.com * licensed hereunder.  You may use the software subject to the license
1012855Sgabeblack@google.com * terms below provided that you ensure that this notice is replicated
1112855Sgabeblack@google.com * unmodified and in its entirety in all distributions of the software,
1212855Sgabeblack@google.com * modified or unmodified, in source code or in binary form.
1312855Sgabeblack@google.com *
1412855Sgabeblack@google.com * Redistribution and use in source and binary forms, with or without
1512855Sgabeblack@google.com * modification, are permitted provided that the following conditions are
1612855Sgabeblack@google.com * met: redistributions of source code must retain the above copyright
1712855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer;
1812855Sgabeblack@google.com * redistributions in binary form must reproduce the above copyright
1912855Sgabeblack@google.com * notice, this list of conditions and the following disclaimer in the
2012855Sgabeblack@google.com * documentation and/or other materials provided with the distribution;
2112855Sgabeblack@google.com * neither the name of the copyright holders nor the names of its
2212855Sgabeblack@google.com * contributors may be used to endorse or promote products derived from
2312855Sgabeblack@google.com * this software without specific prior written permission.
2412855Sgabeblack@google.com *
2512855Sgabeblack@google.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2612855Sgabeblack@google.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2712855Sgabeblack@google.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2812855Sgabeblack@google.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2912855Sgabeblack@google.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3012855Sgabeblack@google.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3112855Sgabeblack@google.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3212855Sgabeblack@google.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3312855Sgabeblack@google.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3412855Sgabeblack@google.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3512855Sgabeblack@google.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3612855Sgabeblack@google.com *
3712855Sgabeblack@google.com * Authors: Andreas Sandberg
3812855Sgabeblack@google.com */
3912855Sgabeblack@google.com
4012855Sgabeblack@google.com#include "debug/VIOPci.hh"
4112855Sgabeblack@google.com#include "dev/virtio/pci.hh"
4212855Sgabeblack@google.com#include "mem/packet_access.hh"
4312855Sgabeblack@google.com#include "params/PciVirtIO.hh"
4412855Sgabeblack@google.com
4512855Sgabeblack@google.comPciVirtIO::PciVirtIO(const Params *params)
4612855Sgabeblack@google.com    : PciDevice(params), vio(*params->vio),
4712855Sgabeblack@google.com      callbackKick(this)
4812855Sgabeblack@google.com{
4912855Sgabeblack@google.com    // Override the subsystem ID with the device ID from VirtIO
5012855Sgabeblack@google.com    config.subsystemID = htole(vio.deviceId);
5112855Sgabeblack@google.com    BARSize[0] = BAR0_SIZE_BASE + vio.configSize;
5212855Sgabeblack@google.com
5312855Sgabeblack@google.com    vio.registerKickCallback(&callbackKick);
5412855Sgabeblack@google.com}
5512855Sgabeblack@google.com
5612855Sgabeblack@google.comPciVirtIO::~PciVirtIO()
5712855Sgabeblack@google.com{
5812855Sgabeblack@google.com}
5912855Sgabeblack@google.com
6012855Sgabeblack@google.comTick
6112855Sgabeblack@google.comPciVirtIO::read(PacketPtr pkt)
6212855Sgabeblack@google.com{
6312855Sgabeblack@google.com    const unsigned M5_VAR_USED size(pkt->getSize());
6412855Sgabeblack@google.com    int bar;
6512855Sgabeblack@google.com    Addr offset;
6612855Sgabeblack@google.com    if (!getBAR(pkt->getAddr(), bar, offset))
6712855Sgabeblack@google.com        panic("Invalid PCI memory access to unmapped memory.\n");
6812855Sgabeblack@google.com    assert(bar == 0);
6912855Sgabeblack@google.com
7012855Sgabeblack@google.com    DPRINTF(VIOPci, "Reading offset 0x%x [len: %i]\n", offset, size);
7112855Sgabeblack@google.com
7212855Sgabeblack@google.com    // Forward device configuration writes to the device VirtIO model
7312855Sgabeblack@google.com    if (offset >= OFF_VIO_DEVICE) {
7412855Sgabeblack@google.com        vio.readConfig(pkt, offset - OFF_VIO_DEVICE);
7512855Sgabeblack@google.com        return 0;
7612855Sgabeblack@google.com    }
7712855Sgabeblack@google.com
7812855Sgabeblack@google.com    pkt->allocate();
7912855Sgabeblack@google.com
8012855Sgabeblack@google.com    switch(offset) {
8112855Sgabeblack@google.com      case OFF_DEVICE_FEATURES:
8212855Sgabeblack@google.com        DPRINTF(VIOPci, "   DEVICE_FEATURES request\n");
8312855Sgabeblack@google.com        assert(size == sizeof(uint32_t));
8412855Sgabeblack@google.com        pkt->set<uint32_t>(vio.deviceFeatures);
8512855Sgabeblack@google.com        break;
8612855Sgabeblack@google.com
8712855Sgabeblack@google.com      case OFF_GUEST_FEATURES:
8812855Sgabeblack@google.com        DPRINTF(VIOPci, "   GUEST_FEATURES request\n");
8912855Sgabeblack@google.com        assert(size == sizeof(uint32_t));
9012855Sgabeblack@google.com        pkt->set<uint32_t>(vio.getGuestFeatures());
9112855Sgabeblack@google.com        break;
9212855Sgabeblack@google.com
9312855Sgabeblack@google.com      case OFF_QUEUE_ADDRESS:
9412855Sgabeblack@google.com        DPRINTF(VIOPci, "   QUEUE_ADDRESS request\n");
9512855Sgabeblack@google.com        assert(size == sizeof(uint32_t));
9612855Sgabeblack@google.com        pkt->set<uint32_t>(vio.getQueueAddress());
9712855Sgabeblack@google.com        break;
9812855Sgabeblack@google.com
9912855Sgabeblack@google.com      case OFF_QUEUE_SIZE:
10012855Sgabeblack@google.com        DPRINTF(VIOPci, "   QUEUE_SIZE request\n");
10112855Sgabeblack@google.com        assert(size == sizeof(uint16_t));
10212855Sgabeblack@google.com        pkt->set<uint16_t>(vio.getQueueSize());
10312855Sgabeblack@google.com        break;
10412855Sgabeblack@google.com
10512855Sgabeblack@google.com      case OFF_QUEUE_SELECT:
10612855Sgabeblack@google.com        DPRINTF(VIOPci, "   QUEUE_SELECT\n");
10712855Sgabeblack@google.com        assert(size == sizeof(uint16_t));
10812855Sgabeblack@google.com        pkt->set<uint16_t>(vio.getQueueSelect());
10912855Sgabeblack@google.com        break;
11012855Sgabeblack@google.com
11112855Sgabeblack@google.com      case OFF_QUEUE_NOTIFY:
11212855Sgabeblack@google.com        DPRINTF(VIOPci, "   QUEUE_NOTIFY request\n");
11312855Sgabeblack@google.com        assert(size == sizeof(uint16_t));
11412855Sgabeblack@google.com        pkt->set<uint16_t>(queueNotify);
11512855Sgabeblack@google.com        break;
11612855Sgabeblack@google.com
11712855Sgabeblack@google.com      case OFF_DEVICE_STATUS:
11812855Sgabeblack@google.com        DPRINTF(VIOPci, "   DEVICE_STATUS request\n");
11912855Sgabeblack@google.com        assert(size == sizeof(uint8_t));
12012855Sgabeblack@google.com        pkt->set<uint8_t>(vio.getDeviceStatus());
12112855Sgabeblack@google.com        break;
12212855Sgabeblack@google.com
12312855Sgabeblack@google.com      case OFF_ISR_STATUS: {
12412855Sgabeblack@google.com          DPRINTF(VIOPci, "   ISR_STATUS\n");
12512855Sgabeblack@google.com          assert(size == sizeof(uint8_t));
12612855Sgabeblack@google.com          uint8_t isr_status(interruptDeliveryPending ? 1 : 0);
12712855Sgabeblack@google.com          interruptDeliveryPending = false;
12812855Sgabeblack@google.com          pkt->set<uint8_t>(isr_status);
12912855Sgabeblack@google.com      } break;
13012855Sgabeblack@google.com
13112855Sgabeblack@google.com      default:
13212855Sgabeblack@google.com        panic("Unhandled read offset (0x%x)\n", offset);
13312855Sgabeblack@google.com    }
13412855Sgabeblack@google.com
13512855Sgabeblack@google.com    return 0;
13612855Sgabeblack@google.com}
13712855Sgabeblack@google.com
13812855Sgabeblack@google.comTick
13912855Sgabeblack@google.comPciVirtIO::write(PacketPtr pkt)
14012855Sgabeblack@google.com{
14112855Sgabeblack@google.com    const unsigned M5_VAR_USED size(pkt->getSize());
14212855Sgabeblack@google.com    int bar;
14312855Sgabeblack@google.com    Addr offset;
14412855Sgabeblack@google.com    if (!getBAR(pkt->getAddr(), bar, offset))
145        panic("Invalid PCI memory access to unmapped memory.\n");
146    assert(bar == 0);
147
148    DPRINTF(VIOPci, "Writing offset 0x%x [len: %i]\n", offset, size);
149
150    // Forward device configuration writes to the device VirtIO model
151    if (offset >= OFF_VIO_DEVICE) {
152        vio.writeConfig(pkt, offset - OFF_VIO_DEVICE);
153        return 0;
154    }
155
156    pkt->allocate();
157
158    switch(offset) {
159      case OFF_DEVICE_FEATURES:
160        warn("Guest tried to write device features.");
161        break;
162
163      case OFF_GUEST_FEATURES:
164        DPRINTF(VIOPci, "   WRITE GUEST_FEATURES request\n");
165        assert(size == sizeof(uint32_t));
166        vio.setGuestFeatures(pkt->get<uint32_t>());
167        break;
168
169      case OFF_QUEUE_ADDRESS:
170        DPRINTF(VIOPci, "   WRITE QUEUE_ADDRESS\n");
171        assert(size == sizeof(uint32_t));
172        vio.setQueueAddress(pkt->get<uint32_t>());
173        break;
174
175      case OFF_QUEUE_SIZE:
176        panic("Guest tried to write queue size.");
177        break;
178
179      case OFF_QUEUE_SELECT:
180        DPRINTF(VIOPci, "   WRITE QUEUE_SELECT\n");
181        assert(size == sizeof(uint16_t));
182        vio.setQueueSelect(pkt->get<uint16_t>());
183        break;
184
185      case OFF_QUEUE_NOTIFY:
186        DPRINTF(VIOPci, "   WRITE QUEUE_NOTIFY\n");
187        assert(size == sizeof(uint16_t));
188        queueNotify = pkt->get<uint16_t>();
189        vio.onNotify(queueNotify);
190        break;
191
192      case OFF_DEVICE_STATUS: {
193          assert(size == sizeof(uint8_t));
194          uint8_t status(pkt->get<uint8_t>());
195          DPRINTF(VIOPci, "VirtIO set status: 0x%x\n", status);
196          vio.setDeviceStatus(status);
197      } break;
198
199      case OFF_ISR_STATUS:
200        warn("Guest tried to write ISR status.");
201        break;
202
203      default:
204        panic("Unhandled read offset (0x%x)\n", offset);
205    }
206
207    return 0;
208}
209
210void
211PciVirtIO::kick()
212{
213    DPRINTF(VIOPci, "kick(): Sending interrupt...\n");
214    interruptDeliveryPending = true;
215    intrPost();
216}
217
218PciVirtIO *
219PciVirtIOParams::create()
220{
221    return new PciVirtIO(this);
222}
223