gem5  v20.1.0.0
pci.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2014, 2017 ARM Limited
3  * All rights reserved
4  *
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.
13  *
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.
24  *
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.
36  */
37 
38 #include "dev/virtio/pci.hh"
39 
40 #include "base/bitfield.hh"
41 #include "debug/VIOIface.hh"
42 #include "mem/packet_access.hh"
43 #include "params/PciVirtIO.hh"
44 
46  : PciDevice(params), queueNotify(0), interruptDeliveryPending(false),
47  vio(*params->vio)
48 {
49  // Override the subsystem ID with the device ID from VirtIO
51 
52  // The kernel driver expects the BAR size to be an exact power of
53  // two. Nothing else is supported. Therefore, we need to force
54  // that alignment here. We do not touch vio.configSize as this is
55  // used to check accesses later on.
57 
58  vio.registerKickCallback([this]() { kick(); });
59 }
60 
62 {
63 }
64 
65 Tick
67 {
68  const unsigned M5_VAR_USED size(pkt->getSize());
69  int bar;
70  Addr offset;
71  if (!getBAR(pkt->getAddr(), bar, offset))
72  panic("Invalid PCI memory access to unmapped memory.\n");
73  assert(bar == 0);
74 
75  DPRINTF(VIOIface, "Reading offset 0x%x [len: %i]\n", offset, size);
76 
77  // Forward device configuration writes to the device VirtIO model
78  if (offset >= OFF_VIO_DEVICE) {
80  return 0;
81  }
82 
83  pkt->makeResponse();
84 
85  switch(offset) {
87  DPRINTF(VIOIface, " DEVICE_FEATURES request\n");
88  assert(size == sizeof(uint32_t));
89  pkt->setLE<uint32_t>(vio.deviceFeatures);
90  break;
91 
92  case OFF_GUEST_FEATURES:
93  DPRINTF(VIOIface, " GUEST_FEATURES request\n");
94  assert(size == sizeof(uint32_t));
95  pkt->setLE<uint32_t>(vio.getGuestFeatures());
96  break;
97 
98  case OFF_QUEUE_ADDRESS:
99  DPRINTF(VIOIface, " QUEUE_ADDRESS request\n");
100  assert(size == sizeof(uint32_t));
101  pkt->setLE<uint32_t>(vio.getQueueAddress());
102  break;
103 
104  case OFF_QUEUE_SIZE:
105  DPRINTF(VIOIface, " QUEUE_SIZE request\n");
106  assert(size == sizeof(uint16_t));
107  pkt->setLE<uint16_t>(vio.getQueueSize());
108  break;
109 
110  case OFF_QUEUE_SELECT:
111  DPRINTF(VIOIface, " QUEUE_SELECT\n");
112  assert(size == sizeof(uint16_t));
113  pkt->setLE<uint16_t>(vio.getQueueSelect());
114  break;
115 
116  case OFF_QUEUE_NOTIFY:
117  DPRINTF(VIOIface, " QUEUE_NOTIFY request\n");
118  assert(size == sizeof(uint16_t));
119  pkt->setLE<uint16_t>(queueNotify);
120  break;
121 
122  case OFF_DEVICE_STATUS:
123  DPRINTF(VIOIface, " DEVICE_STATUS request\n");
124  assert(size == sizeof(uint8_t));
125  pkt->setLE<uint8_t>(vio.getDeviceStatus());
126  break;
127 
128  case OFF_ISR_STATUS: {
129  DPRINTF(VIOIface, " ISR_STATUS\n");
130  assert(size == sizeof(uint8_t));
131  const uint8_t isr_status(interruptDeliveryPending ? 1 : 0);
133  interruptDeliveryPending = false;
134  intrClear();
135  }
136  pkt->setLE<uint8_t>(isr_status);
137  } break;
138 
139  default:
140  panic("Unhandled read offset (0x%x)\n", offset);
141  }
142 
143  return 0;
144 }
145 
146 Tick
148 {
149  const unsigned M5_VAR_USED size(pkt->getSize());
150  int bar;
151  Addr offset;
152  if (!getBAR(pkt->getAddr(), bar, offset))
153  panic("Invalid PCI memory access to unmapped memory.\n");
154  assert(bar == 0);
155 
156  DPRINTF(VIOIface, "Writing offset 0x%x [len: %i]\n", offset, size);
157 
158  // Forward device configuration writes to the device VirtIO model
159  if (offset >= OFF_VIO_DEVICE) {
161  return 0;
162  }
163 
164  pkt->makeResponse();
165 
166  switch(offset) {
167  case OFF_DEVICE_FEATURES:
168  warn("Guest tried to write device features.");
169  break;
170 
171  case OFF_GUEST_FEATURES:
172  DPRINTF(VIOIface, " WRITE GUEST_FEATURES request\n");
173  assert(size == sizeof(uint32_t));
174  vio.setGuestFeatures(pkt->getLE<uint32_t>());
175  break;
176 
177  case OFF_QUEUE_ADDRESS:
178  DPRINTF(VIOIface, " WRITE QUEUE_ADDRESS\n");
179  assert(size == sizeof(uint32_t));
180  vio.setQueueAddress(pkt->getLE<uint32_t>());
181  break;
182 
183  case OFF_QUEUE_SIZE:
184  panic("Guest tried to write queue size.");
185  break;
186 
187  case OFF_QUEUE_SELECT:
188  DPRINTF(VIOIface, " WRITE QUEUE_SELECT\n");
189  assert(size == sizeof(uint16_t));
190  vio.setQueueSelect(pkt->getLE<uint16_t>());
191  break;
192 
193  case OFF_QUEUE_NOTIFY:
194  DPRINTF(VIOIface, " WRITE QUEUE_NOTIFY\n");
195  assert(size == sizeof(uint16_t));
196  queueNotify = pkt->getLE<uint16_t>();
198  break;
199 
200  case OFF_DEVICE_STATUS: {
201  assert(size == sizeof(uint8_t));
202  uint8_t status(pkt->getLE<uint8_t>());
203  DPRINTF(VIOIface, "VirtIO set status: 0x%x\n", status);
205  } break;
206 
207  case OFF_ISR_STATUS:
208  warn("Guest tried to write ISR status.");
209  break;
210 
211  default:
212  panic("Unhandled read offset (0x%x)\n", offset);
213  }
214 
215  return 0;
216 }
217 
218 void
220 {
221  DPRINTF(VIOIface, "kick(): Sending interrupt...\n");
223  intrPost();
224 }
225 
226 PciVirtIO *
227 PciVirtIOParams::create()
228 {
229  return new PciVirtIO(this);
230 }
VirtIODeviceBase::onNotify
void onNotify(QueueID index)
Driver is requesting service.
Definition: base.cc:372
ArmISA::status
Bitfield< 5, 0 > status
Definition: miscregs_types.hh:417
warn
#define warn(...)
Definition: logging.hh:239
PciVirtIO::~PciVirtIO
virtual ~PciVirtIO()
Definition: pci.cc:61
Packet::getAddr
Addr getAddr() const
Definition: packet.hh:754
PciVirtIO::BAR0_SIZE_BASE
static const Addr BAR0_SIZE_BASE
Definition: pci.hh:75
VirtIODeviceBase::readConfig
virtual void readConfig(PacketPtr pkt, Addr cfgOffset)
Read from the configuration space of a device.
Definition: base.cc:408
PciVirtIO::OFF_QUEUE_NOTIFY
static const Addr OFF_QUEUE_NOTIFY
Definition: pci.hh:68
alignToPowerOfTwo
uint64_t alignToPowerOfTwo(uint64_t val)
Align to the next highest power of two.
Definition: bitfield.hh:316
PciVirtIO::PciVirtIO
PciVirtIO(const Params *params)
Definition: pci.cc:45
VirtIODeviceBase::getDeviceStatus
DeviceStatus getDeviceStatus() const
Retrieve the device status.
Definition: base.hh:826
htole
T htole(T value)
Definition: byteswap.hh:140
Tick
uint64_t Tick
Tick count type.
Definition: types.hh:63
PciVirtIO::OFF_QUEUE_SELECT
static const Addr OFF_QUEUE_SELECT
Definition: pci.hh:67
PciDevice::config
PCIConfig config
The current config space.
Definition: device.hh:72
PciVirtIO::OFF_ISR_STATUS
static const Addr OFF_ISR_STATUS
Definition: pci.hh:70
VirtIODeviceBase::getQueueAddress
uint32_t getQueueAddress() const
Get the host physical address of the currently active queue.
Definition: base.cc:469
PciDevice::intrClear
void intrClear()
Definition: device.hh:199
VirtIODeviceBase::getGuestFeatures
FeatureBits getGuestFeatures() const
Get features accepted by the guest driver.
Definition: base.hh:841
Packet::getSize
unsigned getSize() const
Definition: packet.hh:764
VirtIODeviceBase::deviceFeatures
const FeatureBits deviceFeatures
Feature set offered by the device.
Definition: base.hh:850
PciVirtIO::queueNotify
VirtIODeviceBase::QueueID queueNotify
Definition: pci.hh:78
PciVirtIO::write
Tick write(PacketPtr pkt)
Pure virtual function that the device must implement.
Definition: pci.cc:147
VirtIODeviceBase::setQueueAddress
void setQueueAddress(uint32_t address)
Change the host physical address of the currently active queue.
Definition: base.cc:463
VirtIODeviceBase::getQueueSelect
QueueID getQueueSelect() const
Get the currently active queue.
Definition: base.hh:771
PciVirtIO::OFF_VIO_DEVICE
static const Addr OFF_VIO_DEVICE
Definition: pci.hh:71
PciDevice::BARSize
uint32_t BARSize[6]
The size of the BARs.
Definition: device.hh:106
VirtIODeviceBase::configSize
const size_t configSize
Size of the device's configuration space.
Definition: base.hh:847
bitfield.hh
PCIConfig::subsystemID
uint16_t subsystemID
Definition: pcireg.h:72
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:234
PciVirtIO::kick
void kick()
Definition: pci.cc:219
PciVirtIO::OFF_QUEUE_SIZE
static const Addr OFF_QUEUE_SIZE
Definition: pci.hh:66
pci.hh
VirtIODeviceBase::getQueueSize
uint16_t getQueueSize() const
Get the size (descriptors) of the currently active queue.
Definition: base.hh:809
PciVirtIO::OFF_DEVICE_FEATURES
static const Addr OFF_DEVICE_FEATURES
Offsets into VirtIO header (BAR0 relative).
Definition: pci.hh:63
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
Packet::makeResponse
void makeResponse()
Take a request packet and modify it in place to be suitable for returning as a response to that reque...
Definition: packet.hh:1004
PciVirtIO::vio
VirtIODeviceBase & vio
Definition: pci.hh:82
packet_access.hh
VirtIODeviceBase::setGuestFeatures
void setGuestFeatures(FeatureBits features)
Set feature bits accepted by the guest driver.
Definition: base.cc:384
PciVirtIO::OFF_QUEUE_ADDRESS
static const Addr OFF_QUEUE_ADDRESS
Definition: pci.hh:65
PciVirtIO
Definition: pci.hh:47
PciVirtIO::OFF_DEVICE_STATUS
static const Addr OFF_DEVICE_STATUS
Definition: pci.hh:69
VirtIODeviceBase::setQueueSelect
void setQueueSelect(QueueID idx)
Change currently active queue.
Definition: base.hh:761
VirtIODeviceBase::deviceId
const DeviceId deviceId
Device ID (sometimes known as subsystem ID)
Definition: base.hh:844
Packet::getLE
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
Definition: packet_access.hh:75
VirtIODeviceBase::setDeviceStatus
void setDeviceStatus(DeviceStatus status)
Update device status and optionally reset device.
Definition: base.cc:398
PciVirtIO::interruptDeliveryPending
bool interruptDeliveryPending
Definition: pci.hh:80
Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:257
Packet::setLE
void setLE(T v)
Set the value in the data pointer to v as little endian.
Definition: packet_access.hh:105
PciDevice::intrPost
void intrPost()
Definition: device.hh:198
PciVirtIO::OFF_GUEST_FEATURES
static const Addr OFF_GUEST_FEATURES
Definition: pci.hh:64
PciDevice::getBAR
int getBAR(Addr addr)
Which base address register (if any) maps the given address?
Definition: device.hh:139
PciVirtIO::read
Tick read(PacketPtr pkt)
Pure virtual function that the device must implement.
Definition: pci.cc:66
PciDevice
PCI device, base implementation is only config space.
Definition: device.hh:66
DmaDevice::Params
DmaDeviceParams Params
Definition: dma_device.hh:171
VirtIODeviceBase::registerKickCallback
void registerKickCallback(const std::function< void()> &callback)
Register a callback to kick the guest through the transport interface.
Definition: base.hh:733
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
ArmISA::offset
Bitfield< 23, 0 > offset
Definition: types.hh:153
VirtIODeviceBase::writeConfig
virtual void writeConfig(PacketPtr pkt, Addr cfgOffset)
Write to the configuration space of a device.
Definition: base.cc:414

Generated on Wed Sep 30 2020 14:02:11 for gem5 by doxygen 1.8.17