gem5 [DEVELOP-FOR-25.0]
Loading...
Searching...
No Matches
device.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2013, 2015 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 * Copyright (c) 2004-2005 The Regents of The University of Michigan
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions are
19 * met: redistributions of source code must retain the above copyright
20 * notice, this list of conditions and the following disclaimer;
21 * redistributions in binary form must reproduce the above copyright
22 * notice, this list of conditions and the following disclaimer in the
23 * documentation and/or other materials provided with the distribution;
24 * neither the name of the copyright holders nor the names of its
25 * contributors may be used to endorse or promote products derived from
26 * this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 */
40
41/* @file
42 * A single PCI device configuration space entry.
43 */
44
45#include "dev/pci/device.hh"
46
47#include <initializer_list>
48#include <list>
49#include <string>
50#include <vector>
51
52#include "base/inifile.hh"
53#include "base/intmath.hh"
54#include "base/logging.hh"
55#include "base/str.hh"
56#include "base/trace.hh"
57#include "debug/PciBridge.hh"
58#include "debug/PciDevice.hh"
59#include "debug/PciEndpoint.hh"
60#include "mem/packet.hh"
61#include "mem/packet_access.hh"
62#include "sim/byteswap.hh"
63
64namespace gem5
65{
66
67PciDevice::PciDevice(const PciDeviceParams &p,
68 std::initializer_list<PciBar *> BARs_init)
69 : DmaDevice(p),
70 _busAddr(p.pci_bus, p.pci_dev, p.pci_func),
71 PMCAP_BASE(p.PMCAPBaseOffset),
72 PMCAP_ID_OFFSET(p.PMCAPBaseOffset+PMCAP_ID),
73 PMCAP_PC_OFFSET(p.PMCAPBaseOffset+PMCAP_PC),
74 PMCAP_PMCS_OFFSET(p.PMCAPBaseOffset+PMCAP_PMCS),
75 MSICAP_BASE(p.MSICAPBaseOffset),
76 MSIXCAP_BASE(p.MSIXCAPBaseOffset),
77 MSIXCAP_ID_OFFSET(p.MSIXCAPBaseOffset+MSIXCAP_ID),
78 MSIXCAP_MXC_OFFSET(p.MSIXCAPBaseOffset+MSIXCAP_MXC),
79 MSIXCAP_MTAB_OFFSET(p.MSIXCAPBaseOffset+MSIXCAP_MTAB),
80 MSIXCAP_MPBA_OFFSET(p.MSIXCAPBaseOffset+MSIXCAP_MPBA),
81 PXCAP_BASE(p.PXCAPBaseOffset),
82 BARs(BARs_init),
83
84 hostInterface(p.host->registerDevice(this, _busAddr,
85 (PciIntPin)p.InterruptPin)),
86 pioDelay(p.pio_latency),
87 configDelay(p.config_latency)
88{
89 fatal_if(p.InterruptPin >= 5,
90 "Invalid PCI interrupt '%i' specified.", p.InterruptPin);
91
92 int idx = 0;
93 for (auto *bar: BARs) {
94 auto *mu = dynamic_cast<PciMemUpperBar *>(bar);
95 // If this is the upper 32 bits of a memory BAR, try to connect it to
96 // the lower 32 bits.
97 if (mu) {
98 fatal_if(idx == 0,
99 "First BAR in %s is upper 32 bits of a memory BAR.", idx);
100 auto *ml = dynamic_cast<PciMemBar *>(BARs[idx - 1]);
101 fatal_if(!ml, "Upper 32 bits of memory BAR in %s doesn't come "
102 "after the lower 32.");
103 mu->lower(ml);
104 }
105 idx++;
106 }
107
108 _config.common.vendor = htole(p.VendorID);
109 _config.common.device = htole(p.DeviceID);
110 _config.common.command = htole(p.Command);
111 _config.common.status = htole(p.Status);
112 _config.common.revision = htole(p.Revision);
113 _config.common.progIF = htole(p.ProgIF);
114 _config.common.subClassCode = htole(p.SubClassCode);
115 _config.common.classCode = htole(p.ClassCode);
116 _config.common.cacheLineSize = htole(p.CacheLineSize);
117 _config.common.latencyTimer = htole(p.LatencyTimer);
118 _config.common.headerType = htole(p.HeaderType);
119 _config.common.bist = htole(p.BIST);
120 _config.common.capabilityPtr = htole(p.CapabilityPtr);
121 _config.common.interruptPin = htole(p.InterruptPin);
122 _config.common.interruptLine = htole(p.InterruptLine);
123
124 // Initialize the capability lists
125 // These structs are bitunions, meaning the data is stored in host
126 // endianess and must be converted to Little Endian when accessed
127 // by the guest
128 // PMCAP
129 pmcap.pid = (uint16_t)p.PMCAPCapId; // pid.cid
130 pmcap.pid |= (uint16_t)p.PMCAPNextCapability << 8; //pid.next
131 pmcap.pc = p.PMCAPCapabilities;
132 pmcap.pmcs = p.PMCAPCtrlStatus;
133
134 // MSICAP
135 msicap.mid = (uint16_t)p.MSICAPCapId; //mid.cid
136 msicap.mid |= (uint16_t)p.MSICAPNextCapability << 8; //mid.next
137 msicap.mc = p.MSICAPMsgCtrl;
138 msicap.ma = p.MSICAPMsgAddr;
139 msicap.mua = p.MSICAPMsgUpperAddr;
140 msicap.md = p.MSICAPMsgData;
141 msicap.mmask = p.MSICAPMaskBits;
142 msicap.mpend = p.MSICAPPendingBits;
143
144 // MSIXCAP
145 msixcap.mxid = (uint16_t)p.MSIXCAPCapId; //mxid.cid
146 msixcap.mxid |= (uint16_t)p.MSIXCAPNextCapability << 8; //mxid.next
147 msixcap.mxc = p.MSIXMsgCtrl;
148 msixcap.mtab = p.MSIXTableOffset;
149 msixcap.mpba = p.MSIXPbaOffset;
150
151 // allocate MSIX structures if MSIXCAP_BASE
152 // indicates the MSIXCAP is being used by having a
153 // non-zero base address.
154 // The MSIX tables are stored by the guest in
155 // little endian byte-order as according the
156 // PCIe specification. Make sure to take the proper
157 // actions when manipulating these tables on the host
158 uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff;
159 if (MSIXCAP_BASE != 0x0) {
160 int msix_vecs = msixcap_mxc_ts + 1;
161 MSIXTable tmp1 = {{0UL,0UL,0UL,0UL}};
162 msix_table.resize(msix_vecs, tmp1);
163
164 MSIXPbaEntry tmp2 = {0};
165 int pba_size = msix_vecs / MSIXVECS_PER_PBA;
166 if ((msix_vecs % MSIXVECS_PER_PBA) > 0) {
167 pba_size++;
168 }
169 msix_pba.resize(pba_size, tmp2);
170 }
171 MSIX_TABLE_OFFSET = msixcap.mtab & 0xfffffffc;
173 (msixcap_mxc_ts + 1) * sizeof(MSIXTable);
174 MSIX_PBA_OFFSET = msixcap.mpba & 0xfffffffc;
176 ((msixcap_mxc_ts + 1) / MSIXVECS_PER_PBA)
177 * sizeof(MSIXPbaEntry);
178 if (((msixcap_mxc_ts + 1) % MSIXVECS_PER_PBA) > 0) {
179 MSIX_PBA_END += sizeof(MSIXPbaEntry);
180 }
181
182 // PXCAP
183 pxcap.pxid = (uint16_t)p.PXCAPCapId; //pxid.cid
184 pxcap.pxid |= (uint16_t)p.PXCAPNextCapability << 8; //pxid.next
185 pxcap.pxcap = p.PXCAPCapabilities;
186 pxcap.pxdcap = p.PXCAPDevCapabilities;
187 pxcap.pxdc = p.PXCAPDevCtrl;
188 pxcap.pxds = p.PXCAPDevStatus;
189 pxcap.pxlcap = p.PXCAPLinkCap;
190 pxcap.pxlc = p.PXCAPLinkCtrl;
191 pxcap.pxls = p.PXCAPLinkStatus;
192 pxcap.pxscap = p.PXCAPSlotCap;
193 pxcap.pxsc = p.PXCAPSlotCtrl;
194 pxcap.pxss = p.PXCAPSlotStatus;
195 pxcap.pxrcap = p.PXCAPRootCap;
196 pxcap.pxrc = p.PXCAPRootCtrl;
197 pxcap.pxrs = p.PXCAPRootStatus;
198 pxcap.pxdcap2 = p.PXCAPDevCap2;
199 pxcap.pxdc2 = p.PXCAPDevCtrl2;
200 pxcap.pxds2 = p.PXCAPDevStatus2;
201 pxcap.pxlcap2 = p.PXCAPLinkCap2;
202 pxcap.pxlc2 = p.PXCAPLinkCtrl2;
203 pxcap.pxls2 = p.PXCAPLinkStatus2;
204 pxcap.pxscap2 = p.PXCAPSlotCap2;
205 pxcap.pxsc2 = p.PXCAPSlotCtrl2;
206 pxcap.pxss2 = p.PXCAPSlotStatus2;
207}
208
209Tick
211{
212 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
213
214 /* Return 0 for accesses to unimplemented PCI configspace areas */
217 warn_once("Device specific PCI config space "
218 "not implemented for %s!\n", this->name());
219 switch (pkt->getSize()) {
220 case sizeof(uint8_t):
221 pkt->setLE<uint8_t>(0);
222 break;
223 case sizeof(uint16_t):
224 pkt->setLE<uint16_t>(0);
225 break;
226 case sizeof(uint32_t):
227 pkt->setLE<uint32_t>(0);
228 break;
229 default:
230 panic("invalid access size(?) for PCI configspace!\n");
231 }
232 } else if (offset > PCI_CONFIG_SIZE) {
233 panic("Out-of-range access to PCI config space!\n");
234 }
235
236 switch (pkt->getSize()) {
237 case sizeof(uint8_t):
238 pkt->setLE<uint8_t>(_config.data[offset]);
240 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
241 _busAddr.dev, _busAddr.func, offset,
242 (uint32_t)pkt->getLE<uint8_t>());
243 break;
244 case sizeof(uint16_t):
245 pkt->setLE<uint16_t>(*(uint16_t *)&_config.data[offset]);
247 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
248 _busAddr.dev, _busAddr.func, offset,
249 (uint32_t)pkt->getLE<uint16_t>());
250 break;
251 case sizeof(uint32_t):
252 pkt->setLE<uint32_t>(*(uint32_t *)&_config.data[offset]);
254 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
255 _busAddr.dev, _busAddr.func, offset,
256 (uint32_t)pkt->getLE<uint32_t>());
257 break;
258 default:
259 panic("invalid access size(?) for PCI configspace!\n");
260 }
261 pkt->makeAtomicResponse();
262 return configDelay;
263
264}
265
268{
269 AddrRangeList ranges;
270 PciCommandRegister command = letoh(_config.common.command);
271 for (auto *bar: BARs) {
272 if (command.ioSpace && bar->isIo())
273 ranges.push_back(bar->range());
274 if (command.memorySpace && bar->isMem())
275 ranges.push_back(bar->range());
276 }
277 return ranges;
278}
279
280Tick
282{
283 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
284
285 /* No effect if we write to config space that is not implemented*/
288 warn_once("Device specific PCI config space "
289 "not implemented for %s!\n", this->name());
290 switch (pkt->getSize()) {
291 case sizeof(uint8_t):
292 case sizeof(uint16_t):
293 case sizeof(uint32_t):
294 break;
295 default:
296 panic("invalid access size(?) for PCI configspace!\n");
297 }
298 } else if (!isCommonConfig(offset)) {
299 warn_once("Device specific PCI config header "
300 "not implemented for %s!\n", this->name());
301 switch (pkt->getSize()) {
302 case sizeof(uint8_t):
303 case sizeof(uint16_t):
304 case sizeof(uint32_t):
305 break;
306 default:
307 panic("invalid access size(?) for PCI configspace!\n");
308 }
309 } else if (offset > PCI_CONFIG_SIZE) {
310 panic("Out-of-range access to PCI config space!\n");
311 }
312
313 switch (pkt->getSize()) {
314 case sizeof(uint8_t):
315 switch (offset) {
317 _config.common.interruptLine = pkt->getLE<uint8_t>();
318 break;
320 _config.common.cacheLineSize = pkt->getLE<uint8_t>();
321 break;
323 _config.common.latencyTimer = pkt->getLE<uint8_t>();
324 break;
325 /* Do nothing for these read-only registers */
327 case PCI_CLASS_CODE:
328 case PCI_REVISION_ID:
329 break;
330 default:
331 panic("writing to a read only register");
332 }
334 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
335 _busAddr.dev, _busAddr.func, offset,
336 (uint32_t)pkt->getLE<uint8_t>());
337 break;
338 case sizeof(uint16_t):
339 switch (offset) {
340 case PCI_COMMAND:
341 _config.common.command = pkt->getLE<uint8_t>();
342 // IO or memory space may have been enabled/disabled.
343 pioPort.sendRangeChange();
344 break;
345 case PCI_STATUS:
346 _config.common.status = pkt->getLE<uint8_t>();
347 break;
349 _config.common.cacheLineSize = pkt->getLE<uint8_t>();
350 break;
351 default:
352 panic("writing to a read only register");
353 }
355 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
356 _busAddr.dev, _busAddr.func, offset,
357 (uint32_t)pkt->getLE<uint16_t>());
358 break;
359 case sizeof(uint32_t):
360 switch (offset) {
361 case PCI_COMMAND:
362 // This could also clear some of the error bits in the Status
363 // register. However they should never get set, so lets ignore
364 // it for now
365 _config.common.command = pkt->getLE<uint32_t>();
366 // IO or memory space may have been enabled/disabled.
367 pioPort.sendRangeChange();
368 break;
369
370 default:
371 DPRINTF(PciDevice, "Writing to a read only register");
372 }
374 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
375 _busAddr.dev, _busAddr.func, offset,
376 (uint32_t)pkt->getLE<uint32_t>());
377 break;
378 default:
379 panic("invalid access size(?) for PCI configspace!\n");
380 }
381 pkt->makeAtomicResponse();
382 return configDelay;
383}
384
385void
387{
389 sizeof(_config.data) / sizeof(_config.data[0]));
390
391 // serialize the capability list registers
392 paramOut(cp, csprintf("pmcap.pid"), uint16_t(pmcap.pid));
393 paramOut(cp, csprintf("pmcap.pc"), uint16_t(pmcap.pc));
394 paramOut(cp, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs));
395
396 paramOut(cp, csprintf("msicap.mid"), uint16_t(msicap.mid));
397 paramOut(cp, csprintf("msicap.mc"), uint16_t(msicap.mc));
398 paramOut(cp, csprintf("msicap.ma"), uint32_t(msicap.ma));
400 paramOut(cp, csprintf("msicap.md"), uint16_t(msicap.md));
403
404 paramOut(cp, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid));
405 paramOut(cp, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc));
406 paramOut(cp, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab));
407 paramOut(cp, csprintf("msixcap.mpba"), uint32_t(msixcap.mpba));
408
409 // Only serialize if we have a non-zero base address
410 if (MSIXCAP_BASE != 0x0) {
411 uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff;
412 int msix_array_size = msixcap_mxc_ts + 1;
413 int pba_array_size = msix_array_size/MSIXVECS_PER_PBA;
414 if ((msix_array_size % MSIXVECS_PER_PBA) > 0) {
415 pba_array_size++;
416 }
417
418 SERIALIZE_SCALAR(msix_array_size);
419 SERIALIZE_SCALAR(pba_array_size);
420
421 for (int i = 0; i < msix_array_size; i++) {
422 paramOut(cp, csprintf("msix_table[%d].addr_lo", i),
423 msix_table[i].fields.addr_lo);
424 paramOut(cp, csprintf("msix_table[%d].addr_hi", i),
425 msix_table[i].fields.addr_hi);
426 paramOut(cp, csprintf("msix_table[%d].msg_data", i),
427 msix_table[i].fields.msg_data);
428 paramOut(cp, csprintf("msix_table[%d].vec_ctrl", i),
429 msix_table[i].fields.vec_ctrl);
430 }
431 for (int i = 0; i < pba_array_size; i++) {
432 paramOut(cp, csprintf("msix_pba[%d].bits", i),
433 msix_pba[i].bits);
434 }
435 }
436
437 paramOut(cp, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid));
438 paramOut(cp, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap));
439 paramOut(cp, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap));
440 paramOut(cp, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc));
441 paramOut(cp, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds));
442 paramOut(cp, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap));
443 paramOut(cp, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc));
444 paramOut(cp, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls));
445 paramOut(cp, csprintf("pxcap.pxscap"), uint32_t(pxcap.pxscap));
446 paramOut(cp, csprintf("pxcap.pxsc"), uint16_t(pxcap.pxsc));
447 paramOut(cp, csprintf("pxcap.pxss"), uint16_t(pxcap.pxss));
448 paramOut(cp, csprintf("pxcap.pxrcap"), uint16_t(pxcap.pxrcap));
449 paramOut(cp, csprintf("pxcap.pxrc"), uint16_t(pxcap.pxrc));
450 paramOut(cp, csprintf("pxcap.pxrs"), uint32_t(pxcap.pxrs));
451 paramOut(cp, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2));
452 paramOut(cp, csprintf("pxcap.pxdc2"), uint16_t(pxcap.pxdc2));
453 paramOut(cp, csprintf("pxcap.pxds2"), uint16_t(pxcap.pxds2));
454 paramOut(cp, csprintf("pxcap.pxlcap2"), uint32_t(pxcap.pxlcap2));
455 paramOut(cp, csprintf("pxcap.pxlc2"), uint16_t(pxcap.pxlc2));
456 paramOut(cp, csprintf("pxcap.pxls2"), uint16_t(pxcap.pxls2));
457 paramOut(cp, csprintf("pxcap.pxscap2"), uint32_t(pxcap.pxscap2));
458 paramOut(cp, csprintf("pxcap.pxsc2"), uint16_t(pxcap.pxsc2));
459 paramOut(cp, csprintf("pxcap.pxss2"), uint16_t(pxcap.pxss2));
460}
461
462void
464{
466 sizeof(_config.data) / sizeof(_config.data[0]));
467
468 // unserialize the capability list registers
469 uint16_t tmp16;
470 uint32_t tmp32;
471 paramIn(cp, csprintf("pmcap.pid"), tmp16);
472 pmcap.pid = tmp16;
473 paramIn(cp, csprintf("pmcap.pc"), tmp16);
474 pmcap.pc = tmp16;
475 paramIn(cp, csprintf("pmcap.pmcs"), tmp16);
476 pmcap.pmcs = tmp16;
477
478 paramIn(cp, csprintf("msicap.mid"), tmp16);
479 msicap.mid = tmp16;
480 paramIn(cp, csprintf("msicap.mc"), tmp16);
481 msicap.mc = tmp16;
482 paramIn(cp, csprintf("msicap.ma"), tmp32);
483 msicap.ma = tmp32;
485 paramIn(cp, csprintf("msicap.md"), tmp16);;
486 msicap.md = tmp16;
489
490 paramIn(cp, csprintf("msixcap.mxid"), tmp16);
491 msixcap.mxid = tmp16;
492 paramIn(cp, csprintf("msixcap.mxc"), tmp16);
493 msixcap.mxc = tmp16;
494 paramIn(cp, csprintf("msixcap.mtab"), tmp32);
495 msixcap.mtab = tmp32;
496 paramIn(cp, csprintf("msixcap.mpba"), tmp32);
497 msixcap.mpba = tmp32;
498
499 // Only allocate if MSIXCAP_BASE is not 0x0
500 if (MSIXCAP_BASE != 0x0) {
501 int msix_array_size;
502 int pba_array_size;
503
504 UNSERIALIZE_SCALAR(msix_array_size);
505 UNSERIALIZE_SCALAR(pba_array_size);
506
507 MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}};
508 msix_table.resize(msix_array_size, tmp1);
509
510 MSIXPbaEntry tmp2 = {0};
511 msix_pba.resize(pba_array_size, tmp2);
512
513 for (int i = 0; i < msix_array_size; i++) {
514 paramIn(cp, csprintf("msix_table[%d].addr_lo", i),
515 msix_table[i].fields.addr_lo);
516 paramIn(cp, csprintf("msix_table[%d].addr_hi", i),
517 msix_table[i].fields.addr_hi);
518 paramIn(cp, csprintf("msix_table[%d].msg_data", i),
519 msix_table[i].fields.msg_data);
520 paramIn(cp, csprintf("msix_table[%d].vec_ctrl", i),
521 msix_table[i].fields.vec_ctrl);
522 }
523 for (int i = 0; i < pba_array_size; i++) {
524 paramIn(cp, csprintf("msix_pba[%d].bits", i),
525 msix_pba[i].bits);
526 }
527 }
528
529 paramIn(cp, csprintf("pxcap.pxid"), tmp16);
530 pxcap.pxid = tmp16;
531 paramIn(cp, csprintf("pxcap.pxcap"), tmp16);
532 pxcap.pxcap = tmp16;
533 paramIn(cp, csprintf("pxcap.pxdcap"), tmp32);
534 pxcap.pxdcap = tmp32;
535 paramIn(cp, csprintf("pxcap.pxdc"), tmp16);
536 pxcap.pxdc = tmp16;
537 paramIn(cp, csprintf("pxcap.pxds"), tmp16);
538 pxcap.pxds = tmp16;
539 paramIn(cp, csprintf("pxcap.pxlcap"), tmp32);
540 pxcap.pxlcap = tmp32;
541 paramIn(cp, csprintf("pxcap.pxlc"), tmp16);
542 pxcap.pxlc = tmp16;
543 paramIn(cp, csprintf("pxcap.pxls"), tmp16);
544 pxcap.pxls = tmp16;
545 paramIn(cp, csprintf("pxcap.pxscap"), tmp32);
546 pxcap.pxscap = tmp32;
547 paramIn(cp, csprintf("pxcap.pxsc"), tmp16);
548 pxcap.pxsc = tmp16;
549 paramIn(cp, csprintf("pxcap.pxss"), tmp16);
550 pxcap.pxss = tmp16;
551 paramIn(cp, csprintf("pxcap.pxrcap"), tmp16);
552 pxcap.pxrcap = tmp16;
553 paramIn(cp, csprintf("pxcap.pxrc"), tmp16);
554 pxcap.pxrc = tmp16;
555 paramIn(cp, csprintf("pxcap.pxrs"), tmp32);
556 pxcap.pxrs = tmp32;
557 paramIn(cp, csprintf("pxcap.pxdcap2"), tmp32);
558 pxcap.pxdcap2 = tmp32;
559 paramIn(cp, csprintf("pxcap.pxdc2"), tmp16);
560 pxcap.pxdc2 = tmp16;
561 paramIn(cp, csprintf("pxcap.pxds2"), tmp16);
562 pxcap.pxds2 = tmp16;
563 paramIn(cp, csprintf("pxcap.pxlcap2"), tmp32);
564 pxcap.pxlcap2 = tmp32;
565 paramIn(cp, csprintf("pxcap.pxlc2"), tmp16);
566 pxcap.pxlc2 = tmp16;
567 paramIn(cp, csprintf("pxcap.pxls2"), tmp16);
568 pxcap.pxls2 = tmp16;
569 paramIn(cp, csprintf("pxcap.pxscap2"), tmp32);
570 pxcap.pxscap2 = tmp32;
571 paramIn(cp, csprintf("pxcap.pxsc2"), tmp16);
572 pxcap.pxsc2 = tmp16;
573 paramIn(cp, csprintf("pxcap.pxss2"), tmp16);
574 pxcap.pxss2 = tmp16;
575}
576
577PciEndpoint::PciEndpoint(const PciEndpointParams &p)
578 : PciDevice(p, { p.BAR0, p.BAR1, p.BAR2, p.BAR3, p.BAR4, p.BAR5 })
579{
580 fatal_if((_config.common.headerType & 0x7F) != 0, "HeaderType is invalid");
581
582 int idx = 0;
583 for (auto *bar : BARs)
584 _config.type0.baseAddr[idx++] = bar->write(hostInterface, 0);
585
586 _config.type0.cardbusCIS = htole(p.CardbusCIS);
587 _config.type0.subsystemVendorID = htole(p.SubsystemVendorID);
588 _config.type0.subsystemID = htole(p.SubsystemID);
589 _config.type0.expansionROM = htole(p.ExpansionROM);
590
591 // Zero out the 7 bytes of reserved space in the PCI Config space register.
592 bzero(_config.type0.reserved, 7 * sizeof(uint8_t));
593
594 _config.type0.minimumGrant = htole(p.MinimumGrant);
595 _config.type0.maximumLatency = htole(p.MaximumLatency);
596}
597
598Tick
600{
601 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
602
603 if (isCommonConfig(offset)) {
604 return PciDevice::writeConfig(pkt);
606 warn_once("Device specific PCI config space "
607 "not implemented for %s!\n", this->name());
608 switch (pkt->getSize()) {
609 case sizeof(uint8_t):
610 case sizeof(uint16_t):
611 case sizeof(uint32_t):
612 break;
613 default:
614 panic("invalid access size(?) for PCI configspace!\n");
615 }
616 } else if (offset > PCI_CONFIG_SIZE) {
617 panic("Out-of-range access to PCI config space!\n");
618 }
619
620 switch (pkt->getSize()) {
621 case sizeof(uint8_t):
622 switch (offset) {
623 /* Do nothing for these read-only registers */
626 break;
627 default:
628 panic("writing to a read only register");
629 }
631 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
632 _busAddr.dev, _busAddr.func, offset,
633 (uint32_t)pkt->getLE<uint8_t>());
634 break;
635 case sizeof(uint16_t):
636 panic("writing to a read only register");
637 case sizeof(uint32_t):
638 switch (offset) {
639 case PCI0_BASE_ADDR0:
640 case PCI0_BASE_ADDR1:
641 case PCI0_BASE_ADDR2:
642 case PCI0_BASE_ADDR3:
643 case PCI0_BASE_ADDR4:
644 case PCI0_BASE_ADDR5:
645 {
646 int num = PCI0_BAR_NUMBER(offset);
647 auto *bar = BARs[num];
648 _config.type0.baseAddr[num] =
649 htole(bar->write(hostInterface, pkt->getLE<uint32_t>()));
650 pioPort.sendRangeChange();
651 }
652 break;
653
655 if (letoh(pkt->getLE<uint32_t>()) == 0xfffffffe)
656 _config.type0.expansionROM = htole((uint32_t)0xffffffff);
657 else
658 _config.type0.expansionROM = pkt->getLE<uint32_t>();
659 break;
660
661 default:
662 DPRINTF(PciEndpoint, "Writing to a read only register");
663 }
665 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
666 _busAddr.dev, _busAddr.func, offset,
667 (uint32_t)pkt->getLE<uint32_t>());
668 break;
669 default:
670 panic("invalid access size(?) for PCI configspace!\n");
671 }
672 pkt->makeAtomicResponse();
673 return configDelay;
674}
675
676void
678{
680
681 for (int idx = 0; idx < BARs.size(); idx++)
682 BARs[idx]->write(hostInterface, _config.type0.baseAddr[idx]);
683
684 pioPort.sendRangeChange();
685}
686
687PciBridge::PciBridge(const PciBridgeParams &p)
688 : PciDevice(p, { p.BAR0, p.BAR1 })
689{
690 fatal_if((_config.common.headerType & 0x7F) != 1, "HeaderType is invalid");
691
692 int idx = 0;
693 for (auto *bar : BARs)
694 _config.type1.baseAddr[idx++] = bar->write(hostInterface, 0);
695
696 _config.type1.primaryBusNum = htole(p.PrimaryBusNumber);
697 _config.type1.secondaryBusNum = htole(p.SecondaryBusNumber);
698 _config.type1.subordinateBusNum = htole(p.SubordinateBusNumber);
699 _config.type1.secondaryLatencyTimer = htole(p.SecondaryLatencyTimer);
700 _config.type1.ioBase = htole(p.IOBase);
701 _config.type1.ioLimit = htole(p.IOLimit);
702 _config.type1.secondaryStatus = htole(p.SecondaryStatus);
703 _config.type1.memBase = htole(p.MemoryBase);
704 _config.type1.memLimit = htole(p.MemoryLimit);
705 _config.type1.prefetchMemBase = htole(p.PrefetchableMemoryBase);
706 _config.type1.prefetchMemLimit = htole(p.PrefetchableMemoryLimit);
707 _config.type1.prefetchBaseUpper = htole(p.PrefetchableBaseUpper);
708 _config.type1.prefetchLimitUpper = htole(p.PrefetchableLimitUpper);
709 _config.type1.ioBaseUpper = htole(p.IOBaseUpper);
710 _config.type1.ioLimitUpper = htole(p.IOLimitUpper);
711 _config.type1.expansionROM = htole(p.ExpansionROM);
712 _config.type1.bridgeControl = htole(p.BridgeControl);
713}
714
715Tick
717{
718 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
719
720 if (isCommonConfig(offset)) {
721 return PciDevice::writeConfig(pkt);
723 warn_once("Device specific PCI config space "
724 "not implemented for %s!\n", this->name());
725 switch (pkt->getSize()) {
726 case sizeof(uint8_t):
727 case sizeof(uint16_t):
728 case sizeof(uint32_t):
729 break;
730 default:
731 panic("invalid access size(?) for PCI configspace!\n");
732 }
733 } else if (offset > PCI_CONFIG_SIZE) {
734 panic("Out-of-range access to PCI config space!\n");
735 }
736
737 switch (pkt->getSize()) {
738 case sizeof(uint8_t):
739 switch (offset) {
740 case PCI1_PRI_BUS_NUM:
741 _config.type1.primaryBusNum = pkt->getLE<uint8_t>();
742 break;
743 case PCI1_SEC_BUS_NUM:
744 _config.type1.secondaryBusNum = pkt->getLE<uint8_t>();
745 break;
746 case PCI1_SUB_BUS_NUM:
747 _config.type1.subClassCode = pkt->getLE<uint8_t>();
748 break;
750 _config.type1.secondaryLatencyTimer = pkt->getLE<uint8_t>();
751 break;
752 case PCI1_IO_BASE:
753 _config.type1.ioBase = pkt->getLE<uint8_t>();
754 break;
755 case PCI1_IO_LIMIT:
756 _config.type1.ioLimit = pkt->getLE<uint8_t>();
757 break;
758 default:
759 panic("writing to a read only register");
760 }
762 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
763 _busAddr.dev, _busAddr.func, offset,
764 (uint32_t)pkt->getLE<uint8_t>());
765 break;
766 case sizeof(uint16_t):
767 switch (offset) {
769 _config.type1.secondaryStatus = pkt->getLE<uint16_t>();
770 break;
771 case PCI1_MEM_BASE:
772 _config.type1.memBase = pkt->getLE<uint16_t>();
773 break;
774 case PCI1_MEM_LIMIT:
775 _config.type1.memLimit = pkt->getLE<uint16_t>();
776 break;
778 _config.type1.prefetchMemBase = pkt->getLE<uint16_t>();
779 break;
781 _config.type1.prefetchMemLimit = pkt->getLE<uint16_t>();
782 break;
784 _config.type1.ioBaseUpper = pkt->getLE<uint16_t>();
785 break;
787 _config.type1.ioLimitUpper = pkt->getLE<uint16_t>();
788 break;
789 case PCI1_BRIDGE_CTRL:
790 _config.type1.bridgeControl = pkt->getLE<uint16_t>();
791 break;
792 default:
793 panic("writing to a read only register");
794 }
796 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
797 _busAddr.dev, _busAddr.func, offset,
798 (uint32_t)pkt->getLE<uint16_t>());
799 break;
800 case sizeof(uint32_t):
801 switch (offset) {
802 case PCI1_BASE_ADDR0:
803 case PCI1_BASE_ADDR1:
804 {
805 int num = PCI1_BAR_NUMBER(offset);
806 auto *bar = BARs[num];
807 _config.type1.baseAddr[num] = htole(
808 bar->write(hostInterface, pkt->getLE<uint32_t>()));
809 pioPort.sendRangeChange();
810 }
811 break;
813 _config.type1.prefetchBaseUpper = pkt->getLE<uint32_t>();
814 break;
816 _config.type1.prefetchLimitUpper = pkt->getLE<uint32_t>();
817 break;
819 if (letoh(pkt->getLE<uint32_t>()) == 0xfffffffe)
820 _config.type1.expansionROM = htole((uint32_t)0xffffffff);
821 else
822 _config.type1.expansionROM = pkt->getLE<uint32_t>();
823 break;
824 default:
825 panic("writing to a read only register");
826 }
828 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
829 _busAddr.dev, _busAddr.func, offset,
830 (uint32_t)pkt->getLE<uint32_t>());
831 break;
832 default:
833 panic("invalid access size(?) for PCI configspace!\n");
834 }
835 pkt->makeAtomicResponse();
836 return configDelay;
837}
838
839void
841{
843
844 for (int idx = 0; idx < BARs.size(); idx++)
845 BARs[idx]->write(hostInterface, _config.type1.baseAddr[idx]);
846
847 pioPort.sendRangeChange();
848}
849
850} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
DmaDevice(const Params &p)
Addr getAddr() const
Definition packet.hh:807
void setLE(T v)
Set the value in the data pointer to v as little endian.
unsigned getSize() const
Definition packet.hh:817
void makeAtomicResponse()
Definition packet.hh:1074
T getLE() const
Get the data in the packet byte swapped from little endian to host endian.
Tick writeConfig(PacketPtr pkt) override
Write to the PCI config space data that is stored locally.
Definition device.cc:716
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition device.cc:840
PciBridge(const PciBridgeParams &params)
Constructor for PCI Dev.
Definition device.cc:687
const int PMCAP_PC_OFFSET
Definition device.hh:298
PciHost::DeviceInterface hostInterface
Definition device.hh:368
const int MSIXCAP_MTAB_OFFSET
Definition device.hh:308
MSICAP msicap
Definition device.hh:303
PciDevice(const PciDeviceParams &params, std::initializer_list< PciBar * > BARs_init)
Constructor for PCI Dev.
Definition device.cc:67
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition device.cc:463
friend PciEndpoint
Definition device.hh:276
std::vector< MSIXTable > msix_table
MSIX Table and PBA Structures.
Definition device.hh:321
friend PciBridge
Definition device.hh:277
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
Definition device.cc:386
const int MSIXCAP_BASE
Definition device.hh:305
const int PMCAP_BASE
The capability list structures and base addresses.
Definition device.hh:296
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
Definition device.cc:267
int MSIX_PBA_OFFSET
Definition device.hh:312
const int PMCAP_PMCS_OFFSET
Definition device.hh:299
const PciBusAddr _busAddr
Definition device.hh:291
std::vector< MSIXPbaEntry > msix_pba
Definition device.hh:322
virtual Tick readConfig(PacketPtr pkt)
Read from the PCI config space data that is stored locally.
Definition device.cc:210
PCIConfig _config
The current config space.
Definition device.hh:281
MSIXCAP msixcap
Definition device.hh:314
virtual Tick writeConfig(PacketPtr pkt)
Write to the PCI config space data that is stored locally.
Definition device.cc:281
int MSIX_TABLE_OFFSET
Definition device.hh:310
const int MSIXCAP_ID_OFFSET
Definition device.hh:306
const int MSIXCAP_MPBA_OFFSET
Definition device.hh:309
std::vector< PciBar * > BARs
Definition device.hh:324
bool isCommonConfig(Addr offs)
Definition device.hh:284
const int PMCAP_ID_OFFSET
Definition device.hh:297
const int MSIXCAP_MXC_OFFSET
Definition device.hh:307
const int PXCAP_BASE
Definition device.hh:316
const int MSICAP_BASE
Definition device.hh:302
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition device.cc:677
PciEndpoint(const PciEndpointParams &params)
Constructor for PCI Dev.
Definition device.cc:577
Tick writeConfig(PacketPtr pkt) override
Write to the PCI config space data that is stored locally.
Definition device.cc:599
PioPort< PioDevice > pioPort
The pioPort that handles the requests for us and provides us requests that it sees.
Definition io_device.hh:109
virtual Tick write(PacketPtr pkt)=0
Pure virtual function that the device must implement.
#define PCI1_BAR_NUMBER(x)
Definition device.hh:66
#define PCI0_BAR_NUMBER(x)
Definition device.hh:65
std::list< AddrRange > AddrRangeList
Convenience typedef for a collection of address ranges.
Definition addr_range.hh:64
constexpr T bits(T val, unsigned first, unsigned last)
Extract the bitfield from position 'first' to 'last' (inclusive) from 'val' and right justify it.
Definition bitfield.hh:79
#define panic(...)
This implements a cprintf based panic() function.
Definition logging.hh:220
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition logging.hh:268
#define UNSERIALIZE_ARRAY(member, size)
Definition serialize.hh:618
#define SERIALIZE_ARRAY(member, size)
Definition serialize.hh:610
Declaration of IniFile object.
#define warn_once(...)
Definition logging.hh:292
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 23, 0 > offset
Definition types.hh:144
Bitfield< 0 > p
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
T letoh(T value)
Definition byteswap.hh:173
PciIntPin
Definition types.hh:67
std::ostream CheckpointOut
Definition serialize.hh:66
void paramOut(CheckpointOut &cp, const std::string &name, ExtMachInst const &machInst)
Definition types.cc:40
void paramIn(CheckpointIn &cp, const std::string &name, ExtMachInst &machInst)
Definition types.cc:72
uint64_t Tick
Tick count type.
Definition types.hh:58
T htole(T value)
Definition byteswap.hh:172
Packet * PacketPtr
std::string csprintf(const char *format, const Args &...args)
Definition cprintf.hh:161
Declaration of the Packet class.
#define PCI1_PRI_BUS_NUM
Definition pcireg.h:215
#define PCI1_IO_LIMIT_UPPER
Definition pcireg.h:229
#define PCI1_BASE_ADDR1
Definition pcireg.h:214
#define PCI1_PRF_MEM_BASE
Definition pcireg.h:224
#define PCI1_ROM_BASE_ADDR
Definition pcireg.h:231
#define PCI1_SEC_BUS_NUM
Definition pcireg.h:216
#define PCI0_MINIMUM_GRANT
Definition pcireg.h:209
#define PMCAP_PMCS
Definition pcireg.h:254
#define PCI_STATUS
Definition pcireg.h:179
#define PCI0_BASE_ADDR4
Definition pcireg.h:202
#define PCI0_MAXIMUM_LATENCY
Definition pcireg.h:210
#define PCI0_BASE_ADDR0
Definition pcireg.h:198
#define PCI1_SUB_BUS_NUM
Definition pcireg.h:217
#define PCI0_BASE_ADDR5
Definition pcireg.h:203
#define PCI1_SEC_LAT_TIMER
Definition pcireg.h:218
#define PCI0_ROM_BASE_ADDR
Definition pcireg.h:207
#define PCI1_IO_LIMIT
Definition pcireg.h:220
#define PCI1_IO_BASE
Definition pcireg.h:219
#define PCI1_BRIDGE_CTRL
Definition pcireg.h:232
#define PCI_INTERRUPT_PIN
Definition pcireg.h:190
#define PCI0_BASE_ADDR1
Definition pcireg.h:199
#define PCI0_BASE_ADDR2
Definition pcireg.h:200
#define MSIXVECS_PER_PBA
Definition pcireg.h:399
#define PCI0_BASE_ADDR3
Definition pcireg.h:201
#define PCI_INTERRUPT_LINE
Definition pcireg.h:189
#define MSIXCAP_MPBA
Definition pcireg.h:269
#define PCI1_MEM_BASE
Definition pcireg.h:222
#define PCI1_BASE_ADDR0
Definition pcireg.h:213
#define PMCAP_ID
PCIe capability list offsets internal to the entry.
Definition pcireg.h:252
#define PCI1_PRF_BASE_UPPER
Definition pcireg.h:226
#define MSIXCAP_MXC
Definition pcireg.h:267
#define PCI_CACHE_LINE_SIZE
Definition pcireg.h:184
#define PMCAP_PC
Definition pcireg.h:253
#define PCI_DEVICE_SPECIFIC
Definition pcireg.h:54
#define PCI1_PRF_MEM_LIMIT
Definition pcireg.h:225
#define PCI1_PRF_LIMIT_UPPER
Definition pcireg.h:227
#define PCI_COMMAND
Definition pcireg.h:178
#define PCI1_IO_BASE_UPPER
Definition pcireg.h:228
#define PCI_REVISION_ID
Definition pcireg.h:180
#define MSIXCAP_ID
Definition pcireg.h:266
#define PCI_CONFIG_SIZE
Definition pcireg.h:55
#define PCI1_SECONDARY_STATUS
Definition pcireg.h:221
#define PCI_LATENCY_TIMER
Definition pcireg.h:185
#define PCI_CLASS_CODE
Definition pcireg.h:181
#define PCI1_MEM_LIMIT
Definition pcireg.h:223
#define MSIXCAP_MTAB
Definition pcireg.h:268
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568
const std::string & name()
Definition trace.cc:48

Generated on Mon May 26 2025 09:19:07 for gem5 by doxygen 1.13.2