dev: Rework how PCI BARs are set up in python and C++.
In python, the BARs had been configured using three arrays and a scalar
parameter. The arrays tracked the BAR value in the config, whether the
BAR was for a "legacy" IO range, and the size of the BAR, and the
scalar parameter was an offset for the "legacy" IO addresses to map
into the host physical address space. The nature of a BAR was implied
by its raw config space value, with each of the control bits (IO vs.
memory, 64 bit, reserved bits) encoded directly in the value.
Now, the BARs are represented by objects which have different types
depending on what type of BAR they are. There's one for IO, one for
memory, one for the upper 32 bits of a 64 bit BAR (so indices work
out), and one for legacy IO ranges. Each type has parameters which
are appropriate for it, and they're parameters are all grouped together
as a unit instead of being spread across all the previous values.
The legacy IO offset has been removed, since these addresses can be
offset like any other IO address. They can be represented naturally
in the config using their typical IO port numbers, and still be turned
into an address that gem5 will handle correctly in the back end.
Unfortunately, this exposes a problem in the config system where
a VectorParam can't be overwritten successfully one element at a time,
at least when dealing with SimObject classes. It might work with
actual SimObjects in a config, but I haven't tried it. If you were
to do that to, for instance, update the BARs for x86 so that they
used legacy IO ports for the IDE controller, it would complain that
you were trying to instantiate orphaned nodes. Replacing the whole
VectorParam with a new list of BAR objects seems to work, so that's
what's implemented in this change.
On the C++ side, BARs in the config space are treated as flat values
on reads, and are stored in the config structure associated with each
PCI device. On writes, the value is first passed to the BAR object,
and it has a chance to mask any bits which are fixed in hardware and
update its idea of what range it corresponds to in memory.
When sending AddrRanges up to the parent bus to set up routing, the
BARs generate each AddrRange if and only if their type has been
enabled in the config space command register. The BAR object which
represents the upper 32 bits of a 64 bit BAR does not claim to be
IO or memory, and so doesn't contribute a range. It communicates with
the BAR which represents the lower 32 bits, so that that BAR has the
whole base address.
Since the IO or memory BAR enable bits in the command register are now
handled by the PCI device base class, the IDE controller no longer has
to handle that manually. It does still need to keep track of whether
the bus master functionality has been enabled though, which it can
check when those registers are accessed.
There was already a mechanism for decoding addresses based on BARs
in the PCI device base class, but it was overly complicated and not
used consistently across devices. It's been consolidated, and used in
most places where it makes sense.
Finally, a few unnecessary values have been dropped from the base PCI
device's and IDE controller's checkpoint output. These were just local
copies of information already in the BARs, which in turn are already
stored along with the data in the device's config space.
Change-Id: I16d5f8cdf86d7a2d02a6b04d1f9e1b3eb1dd189d
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/35516
Reviewed-by: Gabe Black <gabeblack@google.com>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
14 files changed: