Features/Memory API

From QEMU
Jump to: navigation, search

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.

Patches are queued in

 git://git.kernel.org/pub/scm/virt/kvm/qemu-kvm.git memory-region
 http://git.kernel.org/?p=virt/kvm/qemu-kvm.git;a=shortlog;h=refs/heads/memory-region

for coordination.

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 of opaque 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 a MemoryTransaction object for both reads and writes. Allows a single switch 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.