Features/Memory API
Memory API
Memory on computer systems is a complex thing; typically the CPUs are connected via shared system bus to a memory/pci controller, which directs some accesses to main memory and some to pci cards. Devices can act as additional memory buses (pci bridges). Memory regions can be remapped, hidden, re-enabled, aliased (present at more than one address). Some devices don't decode least significant address bits or most significant address bits, leading to replication of their contents. Some buses or devices have restrictions on alignment or access size; some don't, and they can coexist on the same system.
None of this can be modeled on the old ram_addr_t based API. It has two main deficiencies:
- it is flat: and device has to calculate any transformations that and bridges or controller between itself and the cpu and apply them. This breaks down when the system becomes sufficiently complex.
- it is destructive:
cpu_register_physical_memory()
removes all trace of whatever was previously registered in the region, making it hard/impossible to implement hiding a memory region.
The new API (see memory.[ch]
, docs/memory.txt
) solves those issues by introducing a hierarchical model. MemoryRegion objects can obscure each other, be moved around, be added and removed without destroying information. Each device or controller model only has to take into account interactions with directly connected components; not the entire system.
The memory API defines four different types of memory regions:
- Containers are used to model buses, bridges, or controllers. Each container contains a list of memory regions, each at each own address. Subregions can optionally overlap. Adding and removing subregions may happen dynamically at runtime.
- RAM regions model simple byte arrays backed by RAM cells that can be efficiently accessed by the guest
- MMIO regions model memory areas backed by logic, where accesses have side effects, or where reads return a computed value that is differs from the last write
- Aliases model remapped memory, where a single region is present at multiple addresses, or where a region has a hole in it
Status
Currently the memory API is implemented on top of the old ram_addr_t
API; the two APIs coexist. This severely limits the utility of the new API.
TODO
- Complete conversion of all current users of the old API
- Disallow new uses of the old API
- Reimplement the backing storage as a variable depth radix tree. This will reduce the memory footprint of the memory API.
- Use RCU to control access to memory API data structures instead of
qemu_global_mutex
. - Allow easier registration of mmio callbacks (see below)
- Support address transformation (masking of least significant or most significant address bits)
- Better support for dynamically changing region sizes
- Pass
MemoryRegion
to callbacks instead ofopaque
for better type safety - Debugging support (as gdb python scripts?)
Callback registration proposal
Currently, we support a single .read
and a single .write
callback for the entire region. But that may not be optimal for all devices.
Options include:
- a single
.transaction
callback that receives aMemoryTransaction
object for both reads and writes. Allows a singleswitch
statement instead of duplicating it for reads and writes. - registering a table of callbacks associated with offsets; removes the
switch
statement entirely from user code.