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

Generated on Fri Jun 9 2017 13:03:47 for gem5 by doxygen 1.8.6