gem5 [DEVELOP-FOR-25.1]
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/PciDevice.hh"
58#include "mem/packet.hh"
59#include "mem/packet_access.hh"
60#include "sim/byteswap.hh"
61
62namespace gem5
63{
64
65PciDevice::PciDevice(const PciDeviceParams &p,
66 std::initializer_list<PciBar *> BARs_init)
67 : DmaDevice(p),
68 _devAddr(p.pci_dev, p.pci_func),
69 PMCAP_BASE(p.PMCAPBaseOffset),
70 PMCAP_ID_OFFSET(p.PMCAPBaseOffset + PMCAP_ID),
71 PMCAP_PC_OFFSET(p.PMCAPBaseOffset + PMCAP_PC),
72 PMCAP_PMCS_OFFSET(p.PMCAPBaseOffset + PMCAP_PMCS),
73 MSICAP_BASE(p.MSICAPBaseOffset),
74 MSIXCAP_BASE(p.MSIXCAPBaseOffset),
75 MSIXCAP_ID_OFFSET(p.MSIXCAPBaseOffset + MSIXCAP_ID),
76 MSIXCAP_MXC_OFFSET(p.MSIXCAPBaseOffset + MSIXCAP_MXC),
77 MSIXCAP_MTAB_OFFSET(p.MSIXCAPBaseOffset + MSIXCAP_MTAB),
78 MSIXCAP_MPBA_OFFSET(p.MSIXCAPBaseOffset + MSIXCAP_MPBA),
79 PXCAP_BASE(p.PXCAPBaseOffset),
80 BARs(BARs_init),
81 upstreamInterface(p.upstream->registerDevice(this, _devAddr,
82 (PciIntPin)p.InterruptPin)),
83 pioDelay(p.pio_latency),
84 configDelay(p.config_latency)
85{
86 fatal_if(p.InterruptPin >= 5,
87 "Invalid PCI interrupt '%i' specified.", p.InterruptPin);
88
89 int idx = 0;
90 for (auto *bar: BARs) {
91 auto *mu = dynamic_cast<PciMemUpperBar *>(bar);
92 // If this is the upper 32 bits of a memory BAR, try to connect it to
93 // the lower 32 bits.
94 if (mu) {
95 fatal_if(idx == 0,
96 "First BAR in %s is upper 32 bits of a memory BAR.", idx);
97 auto *ml = dynamic_cast<PciMemBar *>(BARs[idx - 1]);
98 fatal_if(!ml, "Upper 32 bits of memory BAR in %s doesn't come "
99 "after the lower 32.");
100 mu->lower(ml);
101 }
102 idx++;
103 }
104
105 _config.common.vendor = htole(p.VendorID);
106 _config.common.device = htole(p.DeviceID);
107 _config.common.command = htole(p.Command);
108 _config.common.status = htole(p.Status);
109 _config.common.revision = htole(p.Revision);
110 _config.common.progIF = htole(p.ProgIF);
111 _config.common.subClassCode = htole(p.SubClassCode);
112 _config.common.classCode = htole(p.ClassCode);
113 _config.common.cacheLineSize = htole(p.CacheLineSize);
114 _config.common.latencyTimer = htole(p.LatencyTimer);
115 _config.common.headerType = htole(p.HeaderType);
116 _config.common.bist = htole(p.BIST);
117 _config.common.capabilityPtr = htole(p.CapabilityPtr);
118 _config.common.interruptPin = htole(p.InterruptPin);
119 _config.common.interruptLine = htole(p.InterruptLine);
120
121 // Initialize the capability lists
122 // These structs are bitunions, meaning the data is stored in host
123 // endianess and must be converted to Little Endian when accessed
124 // by the guest
125 // PMCAP
126 pmcap.pid = (uint16_t)p.PMCAPCapId; // pid.cid
127 pmcap.pid |= (uint16_t)p.PMCAPNextCapability << 8; //pid.next
128 pmcap.pc = p.PMCAPCapabilities;
129 pmcap.pmcs = p.PMCAPCtrlStatus;
130
131 // MSICAP
132 msicap.mid = (uint16_t)p.MSICAPCapId; //mid.cid
133 msicap.mid |= (uint16_t)p.MSICAPNextCapability << 8; //mid.next
134 msicap.mc = p.MSICAPMsgCtrl;
135 msicap.ma = p.MSICAPMsgAddr;
136 msicap.mua = p.MSICAPMsgUpperAddr;
137 msicap.md = p.MSICAPMsgData;
138 msicap.mmask = p.MSICAPMaskBits;
139 msicap.mpend = p.MSICAPPendingBits;
140
141 // MSIXCAP
142 msixcap.mxid = (uint16_t)p.MSIXCAPCapId; //mxid.cid
143 msixcap.mxid |= (uint16_t)p.MSIXCAPNextCapability << 8; //mxid.next
144 msixcap.mxc = p.MSIXMsgCtrl;
145 msixcap.mtab = p.MSIXTableOffset;
146 msixcap.mpba = p.MSIXPbaOffset;
147
148 // allocate MSIX structures if MSIXCAP_BASE
149 // indicates the MSIXCAP is being used by having a
150 // non-zero base address.
151 // The MSIX tables are stored by the guest in
152 // little endian byte-order as according the
153 // PCIe specification. Make sure to take the proper
154 // actions when manipulating these tables on the host
155 uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff;
156 if (MSIXCAP_BASE != 0x0) {
157 int msix_vecs = msixcap_mxc_ts + 1;
158 MSIXTable tmp1 = {{0UL,0UL,0UL,0UL}};
159 msix_table.resize(msix_vecs, tmp1);
160
161 MSIXPbaEntry tmp2 = {0};
162 int pba_size = msix_vecs / MSIXVECS_PER_PBA;
163 if ((msix_vecs % MSIXVECS_PER_PBA) > 0) {
164 pba_size++;
165 }
166 msix_pba.resize(pba_size, tmp2);
167 }
168 MSIX_TABLE_OFFSET = msixcap.mtab & 0xfffffffc;
170 (msixcap_mxc_ts + 1) * sizeof(MSIXTable);
171 MSIX_PBA_OFFSET = msixcap.mpba & 0xfffffffc;
173 ((msixcap_mxc_ts + 1) / MSIXVECS_PER_PBA)
174 * sizeof(MSIXPbaEntry);
175 if (((msixcap_mxc_ts + 1) % MSIXVECS_PER_PBA) > 0) {
176 MSIX_PBA_END += sizeof(MSIXPbaEntry);
177 }
178
179 // PXCAP
180 pxcap.pxid = (uint16_t)p.PXCAPCapId; //pxid.cid
181 pxcap.pxid |= (uint16_t)p.PXCAPNextCapability << 8; //pxid.next
182 pxcap.pxcap = p.PXCAPCapabilities;
183 pxcap.pxdcap = p.PXCAPDevCapabilities;
184 pxcap.pxdc = p.PXCAPDevCtrl;
185 pxcap.pxds = p.PXCAPDevStatus;
186 pxcap.pxlcap = p.PXCAPLinkCap;
187 pxcap.pxlc = p.PXCAPLinkCtrl;
188 pxcap.pxls = p.PXCAPLinkStatus;
189 pxcap.pxscap = p.PXCAPSlotCap;
190 pxcap.pxsc = p.PXCAPSlotCtrl;
191 pxcap.pxss = p.PXCAPSlotStatus;
192 pxcap.pxrcap = p.PXCAPRootCap;
193 pxcap.pxrc = p.PXCAPRootCtrl;
194 pxcap.pxrs = p.PXCAPRootStatus;
195 pxcap.pxdcap2 = p.PXCAPDevCap2;
196 pxcap.pxdc2 = p.PXCAPDevCtrl2;
197 pxcap.pxds2 = p.PXCAPDevStatus2;
198 pxcap.pxlcap2 = p.PXCAPLinkCap2;
199 pxcap.pxlc2 = p.PXCAPLinkCtrl2;
200 pxcap.pxls2 = p.PXCAPLinkStatus2;
201 pxcap.pxscap2 = p.PXCAPSlotCap2;
202 pxcap.pxsc2 = p.PXCAPSlotCtrl2;
203 pxcap.pxss2 = p.PXCAPSlotStatus2;
204}
205
206Tick
208{
209 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
210
211 /* Return 0 for accesses to unimplemented PCI configspace areas */
214 warn_once("Device specific PCI config space "
215 "not implemented for %s!\n", this->name());
216 switch (pkt->getSize()) {
217 case sizeof(uint8_t):
218 pkt->setLE<uint8_t>(0);
219 break;
220 case sizeof(uint16_t):
221 pkt->setLE<uint16_t>(0);
222 break;
223 case sizeof(uint32_t):
224 pkt->setLE<uint32_t>(0);
225 break;
226 default:
227 panic("invalid access size(?) for PCI configspace!\n");
228 }
229 } else if (offset > PCI_CONFIG_SIZE) {
230 panic("Out-of-range access to PCI config space!\n");
231 }
232
233 switch (pkt->getSize()) {
234 case sizeof(uint8_t):
235 pkt->setLE<uint8_t>(_config.data[offset]);
237 "readConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
238 _devAddr.dev, _devAddr.func, offset,
239 (uint32_t)pkt->getLE<uint8_t>());
240 break;
241 case sizeof(uint16_t):
242 pkt->setLE<uint16_t>(*(uint16_t *)&_config.data[offset]);
244 "readConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
245 _devAddr.dev, _devAddr.func, offset,
246 (uint32_t)pkt->getLE<uint16_t>());
247 break;
248 case sizeof(uint32_t):
249 pkt->setLE<uint32_t>(*(uint32_t *)&_config.data[offset]);
251 "readConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
252 _devAddr.dev, _devAddr.func, offset,
253 (uint32_t)pkt->getLE<uint32_t>());
254 break;
255 default:
256 panic("invalid access size(?) for PCI configspace!\n");
257 }
258 pkt->makeAtomicResponse();
259 return configDelay;
260
261}
262
263Tick
265{
266 if (upstreamInterface.configRange().contains(pkt->getAddr())) {
267 return readConfig(pkt);
268 }
269
270 return readDevice(pkt);
271}
272
275{
276 AddrRangeList ranges;
277 PciCommandRegister command = letoh(_config.common.command);
278 for (auto *bar: BARs) {
279 if (command.ioSpace && bar->isIo())
280 ranges.push_back(bar->range());
281 if (command.memorySpace && bar->isMem())
282 ranges.push_back(bar->range());
283 }
284
285 ranges.push_back(upstreamInterface.configRange());
286
287 return ranges;
288}
289
290Tick
292{
293 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
294
295 /* No effect if we write to config space that is not implemented*/
298 warn_once("Device specific PCI config space "
299 "not implemented for %s!\n", this->name());
300 switch (pkt->getSize()) {
301 case sizeof(uint8_t):
302 case sizeof(uint16_t):
303 case sizeof(uint32_t):
304 break;
305 default:
306 panic("invalid access size(?) for PCI configspace!\n");
307 }
308 } else if (!isCommonConfig(offset)) {
309 warn_once("Device specific PCI config header "
310 "not implemented for %s!\n", this->name());
311 switch (pkt->getSize()) {
312 case sizeof(uint8_t):
313 case sizeof(uint16_t):
314 case sizeof(uint32_t):
315 break;
316 default:
317 panic("invalid access size(?) for PCI configspace!\n");
318 }
319 } else if (offset > PCI_CONFIG_SIZE) {
320 panic("Out-of-range access to PCI config space!\n");
321 }
322
323 switch (pkt->getSize()) {
324 case sizeof(uint8_t):
325 switch (offset) {
327 _config.common.interruptLine = pkt->getLE<uint8_t>();
328 break;
330 _config.common.cacheLineSize = pkt->getLE<uint8_t>();
331 break;
333 _config.common.latencyTimer = pkt->getLE<uint8_t>();
334 break;
335 /* Do nothing for these read-only registers */
337 case PCI_CLASS_CODE:
338 case PCI_REVISION_ID:
339 break;
340 default:
341 panic("writing to a read only register");
342 }
344 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
345 _devAddr.dev, _devAddr.func, offset,
346 (uint32_t)pkt->getLE<uint8_t>());
347 break;
348 case sizeof(uint16_t):
349 switch (offset) {
350 case PCI_COMMAND:
351 _config.common.command = pkt->getLE<uint8_t>();
352 // IO or memory space may have been enabled/disabled.
353 pioPort.sendRangeChange();
354 break;
355 case PCI_STATUS:
356 _config.common.status = pkt->getLE<uint8_t>();
357 break;
359 _config.common.cacheLineSize = pkt->getLE<uint8_t>();
360 break;
361 default:
362 panic("writing to a read only register");
363 }
365 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
366 _devAddr.dev, _devAddr.func, offset,
367 (uint32_t)pkt->getLE<uint16_t>());
368 break;
369 case sizeof(uint32_t):
370 switch (offset) {
371 case PCI_COMMAND:
372 // This could also clear some of the error bits in the Status
373 // register. However they should never get set, so lets ignore
374 // it for now
375 _config.common.command = pkt->getLE<uint32_t>();
376 // IO or memory space may have been enabled/disabled.
377 pioPort.sendRangeChange();
378 break;
379
380 default:
381 DPRINTF(PciDevice, "Writing to a read only register");
382 }
384 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
385 _devAddr.dev, _devAddr.func, offset,
386 (uint32_t)pkt->getLE<uint32_t>());
387 break;
388 default:
389 panic("invalid access size(?) for PCI configspace!\n");
390 }
391 pkt->makeAtomicResponse();
392 return configDelay;
393}
394
395Tick
397{
398 if (upstreamInterface.configRange().contains(pkt->getAddr())) {
399 return writeConfig(pkt);
400 }
401
402 return writeDevice(pkt);
403}
404
405void
407{
408 pioPort.sendRangeChange();
409}
410
411void
413{
415 sizeof(_config.data) / sizeof(_config.data[0]));
416
417 // serialize the capability list registers
418 paramOut(cp, csprintf("pmcap.pid"), uint16_t(pmcap.pid));
419 paramOut(cp, csprintf("pmcap.pc"), uint16_t(pmcap.pc));
420 paramOut(cp, csprintf("pmcap.pmcs"), uint16_t(pmcap.pmcs));
421
422 paramOut(cp, csprintf("msicap.mid"), uint16_t(msicap.mid));
423 paramOut(cp, csprintf("msicap.mc"), uint16_t(msicap.mc));
424 paramOut(cp, csprintf("msicap.ma"), uint32_t(msicap.ma));
426 paramOut(cp, csprintf("msicap.md"), uint16_t(msicap.md));
429
430 paramOut(cp, csprintf("msixcap.mxid"), uint16_t(msixcap.mxid));
431 paramOut(cp, csprintf("msixcap.mxc"), uint16_t(msixcap.mxc));
432 paramOut(cp, csprintf("msixcap.mtab"), uint32_t(msixcap.mtab));
433 paramOut(cp, csprintf("msixcap.mpba"), uint32_t(msixcap.mpba));
434
435 // Only serialize if we have a non-zero base address
436 if (MSIXCAP_BASE != 0x0) {
437 uint16_t msixcap_mxc_ts = msixcap.mxc & 0x07ff;
438 int msix_array_size = msixcap_mxc_ts + 1;
439 int pba_array_size = msix_array_size/MSIXVECS_PER_PBA;
440 if ((msix_array_size % MSIXVECS_PER_PBA) > 0) {
441 pba_array_size++;
442 }
443
444 SERIALIZE_SCALAR(msix_array_size);
445 SERIALIZE_SCALAR(pba_array_size);
446
447 for (int i = 0; i < msix_array_size; i++) {
448 paramOut(cp, csprintf("msix_table[%d].addr_lo", i),
449 msix_table[i].fields.addr_lo);
450 paramOut(cp, csprintf("msix_table[%d].addr_hi", i),
451 msix_table[i].fields.addr_hi);
452 paramOut(cp, csprintf("msix_table[%d].msg_data", i),
453 msix_table[i].fields.msg_data);
454 paramOut(cp, csprintf("msix_table[%d].vec_ctrl", i),
455 msix_table[i].fields.vec_ctrl);
456 }
457 for (int i = 0; i < pba_array_size; i++) {
458 paramOut(cp, csprintf("msix_pba[%d].bits", i),
459 msix_pba[i].bits);
460 }
461 }
462
463 paramOut(cp, csprintf("pxcap.pxid"), uint16_t(pxcap.pxid));
464 paramOut(cp, csprintf("pxcap.pxcap"), uint16_t(pxcap.pxcap));
465 paramOut(cp, csprintf("pxcap.pxdcap"), uint32_t(pxcap.pxdcap));
466 paramOut(cp, csprintf("pxcap.pxdc"), uint16_t(pxcap.pxdc));
467 paramOut(cp, csprintf("pxcap.pxds"), uint16_t(pxcap.pxds));
468 paramOut(cp, csprintf("pxcap.pxlcap"), uint32_t(pxcap.pxlcap));
469 paramOut(cp, csprintf("pxcap.pxlc"), uint16_t(pxcap.pxlc));
470 paramOut(cp, csprintf("pxcap.pxls"), uint16_t(pxcap.pxls));
471 paramOut(cp, csprintf("pxcap.pxscap"), uint32_t(pxcap.pxscap));
472 paramOut(cp, csprintf("pxcap.pxsc"), uint16_t(pxcap.pxsc));
473 paramOut(cp, csprintf("pxcap.pxss"), uint16_t(pxcap.pxss));
474 paramOut(cp, csprintf("pxcap.pxrcap"), uint16_t(pxcap.pxrcap));
475 paramOut(cp, csprintf("pxcap.pxrc"), uint16_t(pxcap.pxrc));
476 paramOut(cp, csprintf("pxcap.pxrs"), uint32_t(pxcap.pxrs));
477 paramOut(cp, csprintf("pxcap.pxdcap2"), uint32_t(pxcap.pxdcap2));
478 paramOut(cp, csprintf("pxcap.pxdc2"), uint16_t(pxcap.pxdc2));
479 paramOut(cp, csprintf("pxcap.pxds2"), uint16_t(pxcap.pxds2));
480 paramOut(cp, csprintf("pxcap.pxlcap2"), uint32_t(pxcap.pxlcap2));
481 paramOut(cp, csprintf("pxcap.pxlc2"), uint16_t(pxcap.pxlc2));
482 paramOut(cp, csprintf("pxcap.pxls2"), uint16_t(pxcap.pxls2));
483 paramOut(cp, csprintf("pxcap.pxscap2"), uint32_t(pxcap.pxscap2));
484 paramOut(cp, csprintf("pxcap.pxsc2"), uint16_t(pxcap.pxsc2));
485 paramOut(cp, csprintf("pxcap.pxss2"), uint16_t(pxcap.pxss2));
486}
487
488void
490{
492 sizeof(_config.data) / sizeof(_config.data[0]));
493
494 // unserialize the capability list registers
495 uint16_t tmp16;
496 uint32_t tmp32;
497 paramIn(cp, csprintf("pmcap.pid"), tmp16);
498 pmcap.pid = tmp16;
499 paramIn(cp, csprintf("pmcap.pc"), tmp16);
500 pmcap.pc = tmp16;
501 paramIn(cp, csprintf("pmcap.pmcs"), tmp16);
502 pmcap.pmcs = tmp16;
503
504 paramIn(cp, csprintf("msicap.mid"), tmp16);
505 msicap.mid = tmp16;
506 paramIn(cp, csprintf("msicap.mc"), tmp16);
507 msicap.mc = tmp16;
508 paramIn(cp, csprintf("msicap.ma"), tmp32);
509 msicap.ma = tmp32;
511 paramIn(cp, csprintf("msicap.md"), tmp16);;
512 msicap.md = tmp16;
515
516 paramIn(cp, csprintf("msixcap.mxid"), tmp16);
517 msixcap.mxid = tmp16;
518 paramIn(cp, csprintf("msixcap.mxc"), tmp16);
519 msixcap.mxc = tmp16;
520 paramIn(cp, csprintf("msixcap.mtab"), tmp32);
521 msixcap.mtab = tmp32;
522 paramIn(cp, csprintf("msixcap.mpba"), tmp32);
523 msixcap.mpba = tmp32;
524
525 // Only allocate if MSIXCAP_BASE is not 0x0
526 if (MSIXCAP_BASE != 0x0) {
527 int msix_array_size;
528 int pba_array_size;
529
530 UNSERIALIZE_SCALAR(msix_array_size);
531 UNSERIALIZE_SCALAR(pba_array_size);
532
533 MSIXTable tmp1 = {{0UL, 0UL, 0UL, 0UL}};
534 msix_table.resize(msix_array_size, tmp1);
535
536 MSIXPbaEntry tmp2 = {0};
537 msix_pba.resize(pba_array_size, tmp2);
538
539 for (int i = 0; i < msix_array_size; i++) {
540 paramIn(cp, csprintf("msix_table[%d].addr_lo", i),
541 msix_table[i].fields.addr_lo);
542 paramIn(cp, csprintf("msix_table[%d].addr_hi", i),
543 msix_table[i].fields.addr_hi);
544 paramIn(cp, csprintf("msix_table[%d].msg_data", i),
545 msix_table[i].fields.msg_data);
546 paramIn(cp, csprintf("msix_table[%d].vec_ctrl", i),
547 msix_table[i].fields.vec_ctrl);
548 }
549 for (int i = 0; i < pba_array_size; i++) {
550 paramIn(cp, csprintf("msix_pba[%d].bits", i),
551 msix_pba[i].bits);
552 }
553 }
554
555 paramIn(cp, csprintf("pxcap.pxid"), tmp16);
556 pxcap.pxid = tmp16;
557 paramIn(cp, csprintf("pxcap.pxcap"), tmp16);
558 pxcap.pxcap = tmp16;
559 paramIn(cp, csprintf("pxcap.pxdcap"), tmp32);
560 pxcap.pxdcap = tmp32;
561 paramIn(cp, csprintf("pxcap.pxdc"), tmp16);
562 pxcap.pxdc = tmp16;
563 paramIn(cp, csprintf("pxcap.pxds"), tmp16);
564 pxcap.pxds = tmp16;
565 paramIn(cp, csprintf("pxcap.pxlcap"), tmp32);
566 pxcap.pxlcap = tmp32;
567 paramIn(cp, csprintf("pxcap.pxlc"), tmp16);
568 pxcap.pxlc = tmp16;
569 paramIn(cp, csprintf("pxcap.pxls"), tmp16);
570 pxcap.pxls = tmp16;
571 paramIn(cp, csprintf("pxcap.pxscap"), tmp32);
572 pxcap.pxscap = tmp32;
573 paramIn(cp, csprintf("pxcap.pxsc"), tmp16);
574 pxcap.pxsc = tmp16;
575 paramIn(cp, csprintf("pxcap.pxss"), tmp16);
576 pxcap.pxss = tmp16;
577 paramIn(cp, csprintf("pxcap.pxrcap"), tmp16);
578 pxcap.pxrcap = tmp16;
579 paramIn(cp, csprintf("pxcap.pxrc"), tmp16);
580 pxcap.pxrc = tmp16;
581 paramIn(cp, csprintf("pxcap.pxrs"), tmp32);
582 pxcap.pxrs = tmp32;
583 paramIn(cp, csprintf("pxcap.pxdcap2"), tmp32);
584 pxcap.pxdcap2 = tmp32;
585 paramIn(cp, csprintf("pxcap.pxdc2"), tmp16);
586 pxcap.pxdc2 = tmp16;
587 paramIn(cp, csprintf("pxcap.pxds2"), tmp16);
588 pxcap.pxds2 = tmp16;
589 paramIn(cp, csprintf("pxcap.pxlcap2"), tmp32);
590 pxcap.pxlcap2 = tmp32;
591 paramIn(cp, csprintf("pxcap.pxlc2"), tmp16);
592 pxcap.pxlc2 = tmp16;
593 paramIn(cp, csprintf("pxcap.pxls2"), tmp16);
594 pxcap.pxls2 = tmp16;
595 paramIn(cp, csprintf("pxcap.pxscap2"), tmp32);
596 pxcap.pxscap2 = tmp32;
597 paramIn(cp, csprintf("pxcap.pxsc2"), tmp16);
598 pxcap.pxsc2 = tmp16;
599 paramIn(cp, csprintf("pxcap.pxss2"), tmp16);
600 pxcap.pxss2 = tmp16;
601}
602
603PciEndpoint::PciEndpoint(const PciEndpointParams &p)
604 : PciDevice(p, {p.BAR0, p.BAR1, p.BAR2, p.BAR3, p.BAR4, p.BAR5})
605{
606 fatal_if((_config.common.headerType & 0x7F) != 0, "HeaderType is invalid");
607
608 int idx = 0;
609 for (auto *bar : BARs)
610 _config.type0.baseAddr[idx++] = bar->write(upstreamInterface, 0);
611
612 _config.type0.cardbusCIS = htole(p.CardbusCIS);
613 _config.type0.subsystemVendorID = htole(p.SubsystemVendorID);
614 _config.type0.subsystemID = htole(p.SubsystemID);
615 _config.type0.expansionROM = htole(p.ExpansionROM);
616
617 // Zero out the 7 bytes of reserved space in the PCI Config space register.
618 bzero(_config.type0.reserved, 7 * sizeof(uint8_t));
619
620 _config.type0.minimumGrant = htole(p.MinimumGrant);
621 _config.type0.maximumLatency = htole(p.MaximumLatency);
622}
623
624Tick
626{
627 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
628
629 if (isCommonConfig(offset)) {
630 return PciDevice::writeConfig(pkt);
632 warn_once("Device specific PCI config space "
633 "not implemented for %s!\n", this->name());
634 switch (pkt->getSize()) {
635 case sizeof(uint8_t):
636 case sizeof(uint16_t):
637 case sizeof(uint32_t):
638 break;
639 default:
640 panic("invalid access size(?) for PCI configspace!\n");
641 }
642 } else if (offset > PCI_CONFIG_SIZE) {
643 panic("Out-of-range access to PCI config space!\n");
644 }
645
646 switch (pkt->getSize()) {
647 case sizeof(uint8_t):
648 switch (offset) {
649 /* Do nothing for these read-only registers */
652 break;
653 default:
654 panic("writing to a read only register");
655 }
657 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
658 _devAddr.dev, _devAddr.func, offset,
659 (uint32_t)pkt->getLE<uint8_t>());
660 break;
661 case sizeof(uint16_t):
662 panic("writing to a read only register");
663 case sizeof(uint32_t):
664 switch (offset) {
665 case PCI0_BASE_ADDR0:
666 case PCI0_BASE_ADDR1:
667 case PCI0_BASE_ADDR2:
668 case PCI0_BASE_ADDR3:
669 case PCI0_BASE_ADDR4:
670 case PCI0_BASE_ADDR5:
671 {
672 int num = PCI0_BAR_NUMBER(offset);
673 auto *bar = BARs[num];
674 _config.type0.baseAddr[num] = htole(
675 bar->write(upstreamInterface, pkt->getLE<uint32_t>()));
676 pioPort.sendRangeChange();
677 }
678 break;
679
681 if (letoh(pkt->getLE<uint32_t>()) == 0xfffffffe)
682 _config.type0.expansionROM = htole((uint32_t)0xffffffff);
683 else
684 _config.type0.expansionROM = pkt->getLE<uint32_t>();
685 break;
686
687 default:
688 DPRINTF(PciDevice, "Writing to a read only register");
689 }
691 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
692 _devAddr.dev, _devAddr.func, offset,
693 (uint32_t)pkt->getLE<uint32_t>());
694 break;
695 default:
696 panic("invalid access size(?) for PCI configspace!\n");
697 }
698 pkt->makeAtomicResponse();
699 return configDelay;
700}
701
702void
704{
706
707 for (int idx = 0; idx < BARs.size(); idx++)
708 BARs[idx]->write(upstreamInterface, _config.type0.baseAddr[idx]);
709
710 pioPort.sendRangeChange();
711}
712
713PciType1Device::PciType1Device(const PciType1DeviceParams &p)
714 : PciDevice(p, {p.BAR0, p.BAR1})
715{
716 fatal_if((_config.common.headerType & 0x7F) != 1, "HeaderType is invalid");
717
718 int idx = 0;
719 for (auto *bar : BARs)
720 _config.type1.baseAddr[idx++] = bar->write(upstreamInterface, 0);
721
722 _config.type1.primaryBusNum = htole(p.PrimaryBusNumber);
723 _config.type1.secondaryBusNum = htole(p.SecondaryBusNumber);
724 _config.type1.subordinateBusNum = htole(p.SubordinateBusNumber);
725 _config.type1.secondaryLatencyTimer = htole(p.SecondaryLatencyTimer);
726 _config.type1.ioBase = htole(p.IOBase);
727 _config.type1.ioLimit = htole(p.IOLimit);
728 _config.type1.secondaryStatus = htole(p.SecondaryStatus);
729 _config.type1.memBase = htole(p.MemoryBase);
730 _config.type1.memLimit = htole(p.MemoryLimit);
731 _config.type1.prefetchMemBase = htole(p.PrefetchableMemoryBase);
732 _config.type1.prefetchMemLimit = htole(p.PrefetchableMemoryLimit);
733 _config.type1.prefetchBaseUpper = htole(p.PrefetchableBaseUpper);
734 _config.type1.prefetchLimitUpper = htole(p.PrefetchableLimitUpper);
735 _config.type1.ioBaseUpper = htole(p.IOBaseUpper);
736 _config.type1.ioLimitUpper = htole(p.IOLimitUpper);
737 _config.type1.expansionROM = htole(p.ExpansionROM);
738 _config.type1.bridgeControl = htole(p.BridgeControl);
739}
740
741Tick
743{
744 int offset = pkt->getAddr() & PCI_CONFIG_SIZE;
745
746 if (isCommonConfig(offset)) {
747 return PciDevice::writeConfig(pkt);
749 warn_once("Device specific PCI config space "
750 "not implemented for %s!\n", this->name());
751 switch (pkt->getSize()) {
752 case sizeof(uint8_t):
753 case sizeof(uint16_t):
754 case sizeof(uint32_t):
755 break;
756 default:
757 panic("invalid access size(?) for PCI configspace!\n");
758 }
759 } else if (offset > PCI_CONFIG_SIZE) {
760 panic("Out-of-range access to PCI config space!\n");
761 }
762
763 switch (pkt->getSize()) {
764 case sizeof(uint8_t):
765 switch (offset) {
766 case PCI1_PRI_BUS_NUM:
767 _config.type1.primaryBusNum = pkt->getLE<uint8_t>();
768 break;
769 case PCI1_SEC_BUS_NUM:
770 _config.type1.secondaryBusNum = pkt->getLE<uint8_t>();
771 break;
772 case PCI1_SUB_BUS_NUM:
773 _config.type1.subClassCode = pkt->getLE<uint8_t>();
774 break;
776 _config.type1.secondaryLatencyTimer = pkt->getLE<uint8_t>();
777 break;
778 case PCI1_IO_BASE:
779 _config.type1.ioBase = pkt->getLE<uint8_t>();
780 break;
781 case PCI1_IO_LIMIT:
782 _config.type1.ioLimit = pkt->getLE<uint8_t>();
783 break;
784 default:
785 panic("writing to a read only register");
786 }
788 "writeConfig: dev %#x func %#x reg %#x 1 bytes: data = %#x\n",
789 _devAddr.dev, _devAddr.func, offset,
790 (uint32_t)pkt->getLE<uint8_t>());
791 break;
792 case sizeof(uint16_t):
793 switch (offset) {
795 _config.type1.secondaryStatus = pkt->getLE<uint16_t>();
796 break;
797 case PCI1_MEM_BASE:
798 _config.type1.memBase = pkt->getLE<uint16_t>();
799 break;
800 case PCI1_MEM_LIMIT:
801 _config.type1.memLimit = pkt->getLE<uint16_t>();
802 break;
804 _config.type1.prefetchMemBase = pkt->getLE<uint16_t>();
805 break;
807 _config.type1.prefetchMemLimit = pkt->getLE<uint16_t>();
808 break;
810 _config.type1.ioBaseUpper = pkt->getLE<uint16_t>();
811 break;
813 _config.type1.ioLimitUpper = pkt->getLE<uint16_t>();
814 break;
815 case PCI1_BRIDGE_CTRL:
816 _config.type1.bridgeControl = pkt->getLE<uint16_t>();
817 break;
818 default:
819 panic("writing to a read only register");
820 }
822 "writeConfig: dev %#x func %#x reg %#x 2 bytes: data = %#x\n",
823 _devAddr.dev, _devAddr.func, offset,
824 (uint32_t)pkt->getLE<uint16_t>());
825 break;
826 case sizeof(uint32_t):
827 switch (offset) {
828 case PCI1_BASE_ADDR0:
829 case PCI1_BASE_ADDR1:
830 {
831 int num = PCI1_BAR_NUMBER(offset);
832 auto *bar = BARs[num];
833 _config.type1.baseAddr[num] =
834 htole(bar->write(upstreamInterface, pkt->getLE<uint32_t>()));
835 pioPort.sendRangeChange();
836 }
837 break;
839 _config.type1.prefetchBaseUpper = pkt->getLE<uint32_t>();
840 break;
842 _config.type1.prefetchLimitUpper = pkt->getLE<uint32_t>();
843 break;
845 if (letoh(pkt->getLE<uint32_t>()) == 0xfffffffe)
846 _config.type1.expansionROM = htole((uint32_t)0xffffffff);
847 else
848 _config.type1.expansionROM = pkt->getLE<uint32_t>();
849 break;
850 default:
851 panic("writing to a read only register");
852 }
854 "writeConfig: dev %#x func %#x reg %#x 4 bytes: data = %#x\n",
855 _devAddr.dev, _devAddr.func, offset,
856 (uint32_t)pkt->getLE<uint32_t>());
857 break;
858 default:
859 panic("invalid access size(?) for PCI configspace!\n");
860 }
861 pkt->makeAtomicResponse();
862 return configDelay;
863}
864
865void
867{
869
870 for (int idx = 0; idx < BARs.size(); idx++)
871 BARs[idx]->write(upstreamInterface, _config.type1.baseAddr[idx]);
872
873 pioPort.sendRangeChange();
874}
875
876} // 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.
const int PMCAP_PC_OFFSET
Definition device.hh:320
Tick write(PacketPtr pkt) final
Final implementation of write access from DmaDevice.
Definition device.cc:396
const int MSIXCAP_MTAB_OFFSET
Definition device.hh:330
MSICAP msicap
Definition device.hh:325
PciDevice(const PciDeviceParams &params, std::initializer_list< PciBar * > BARs_init)
Constructor for PCI Dev.
Definition device.cc:65
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition device.cc:489
friend PciEndpoint
Definition device.hh:298
std::vector< MSIXTable > msix_table
MSIX Table and PBA Structures.
Definition device.hh:343
PciUpstream::DeviceInterface upstreamInterface
Definition device.hh:422
void serialize(CheckpointOut &cp) const override
Serialize this object to the given output stream.
Definition device.cc:412
void recvBusChange()
Called to receive a bus number change from the PCI upstream.
Definition device.cc:406
Tick read(PacketPtr pkt) final
Final implementation of read access from PioDevice.
Definition device.cc:264
const int MSIXCAP_BASE
Definition device.hh:327
const int PMCAP_BASE
The capability list structures and base addresses.
Definition device.hh:318
AddrRangeList getAddrRanges() const override
Determine the address ranges that this device responds to.
Definition device.cc:274
int MSIX_PBA_OFFSET
Definition device.hh:334
const int PMCAP_PMCS_OFFSET
Definition device.hh:321
virtual Tick writeDevice(PacketPtr pkt)=0
Write to the PCI device.
std::vector< MSIXPbaEntry > msix_pba
Definition device.hh:344
virtual Tick readConfig(PacketPtr pkt)
Read from the PCI config space data that is stored locally.
Definition device.cc:207
PCIConfig _config
The current config space.
Definition device.hh:303
virtual Tick readDevice(PacketPtr pkt)=0
Read from the PCI device.
MSIXCAP msixcap
Definition device.hh:336
virtual Tick writeConfig(PacketPtr pkt)
Write to the PCI config space data that is stored locally.
Definition device.cc:291
int MSIX_TABLE_OFFSET
Definition device.hh:332
const int MSIXCAP_ID_OFFSET
Definition device.hh:328
const int MSIXCAP_MPBA_OFFSET
Definition device.hh:331
friend PciType1Device
Definition device.hh:299
std::vector< PciBar * > BARs
Definition device.hh:346
bool isCommonConfig(Addr offs)
Definition device.hh:306
const int PMCAP_ID_OFFSET
Definition device.hh:319
const int MSIXCAP_MXC_OFFSET
Definition device.hh:329
const int PXCAP_BASE
Definition device.hh:338
const PciDevAddr _devAddr
Definition device.hh:313
const int MSICAP_BASE
Definition device.hh:324
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition device.cc:703
Tick writeConfig(PacketPtr pkt) override
Write to the PCI config space data that is stored locally.
Definition device.cc:625
Tick writeConfig(PacketPtr pkt) override
Write to the PCI config space data that is stored locally.
Definition device.cc:742
void unserialize(CheckpointIn &cp) override
Reconstruct the state of this object from a checkpoint.
Definition device.cc:866
PioPort< PioDevice > pioPort
The pioPort that handles the requests for us and provides us requests that it sees.
Definition io_device.hh:109
#define PCI1_BAR_NUMBER(x)
Definition device.hh:67
#define PCI0_BAR_NUMBER(x)
Definition device.hh:66
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:74
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 Oct 27 2025 04:13:00 for gem5 by doxygen 1.14.0