Guest memory regions

Use the functions defined in gasp.h to work with memory regions in the guest's physical address space.

See the Virtual Device Developer's API Reference gasp.h and types.h chapters for descriptions of of the functions, data structures, etc. discussed here.

Data elements and their types

The qvm_state_types enumerated values specify the types of resources that the hypervisor supports for guests in its VMs. The qvm_state_block data structure describes a data element in the guest. The type of element a qvm_state_block data structure describes is determined by the qvm_state_types value specified. For example, with its type member set to QST_MEMORY the qvm_state_block location member is a guest-physical address, while with QST_PCI the same member identifies a PCI device through its bus, device, and function numbers.

The gasp_region data structure describes a guest resource, including where a memory region should map in the host system (host-virtual address), and where it should map in the guest. This structure's guest member is a qvm_state_block structure, whose location member refers to different types of resources, depending on the value of qvm_state_types.

When assigning memory regions and other resources in a guest, make sure that you set qvm_state_types to the type of resource you need, and that you set the qvm_state_flags QSF_* and the gasp_region_flags GRF_* flags to define behavior (e.g., read/write/execute), and characteristics (e.g., the region is installed).

Note: Zero-length regions are ignored.

Assigning memory regions

Use the gasp_*() functions to assign a memory region with the characteristics specified in the gasp_region data structure and the behavior specified by the gasp_region_flags GRF_* flags.

Your vdev can assign itself memory for its own use, as follows:

  1. Call gasp_lock() to lock the guest address space to ensure that no other vdev can claim the region you need before you have finished your task.
  2. Call gasp_find_free() or gasp_find_free_range() to find available memory of the QST_* type you specify.
  3. Call gasp_region_set() or gasp_region_set_soft() to assign the memory region.
  4. Call gasp_unlock() to unlock the guest address space and make unassigned regions available to other vdevs.

Assigning memory during startup or after startup is complete

There are some important differences in how you should assign memory to a vdev during a qvm process instance's startup stage and after the startup stage is complete.

The VDEV_CTRL_GUEST_CONFIGURED callback marks the completion of the startup stage; you should write your vdev's control function to handle this callback so that you can implement appropriate behavior before and after your vdev receives this callback (see Lifecycle of a vdev in this chapter, and vdtrace_control() in “The Basics: vdev trace chapter).

Startup

When it is initializing a VM, a qvm process instance is single-threaded. This means that you don't need to call gasp_lock() to lock the guest memory region before you call other gasp_*() functions to find and assign guest memory regions, or call gasp_unlock() to release the remainder of the guest memory when you have finished assigning memory for your vdev.

When your vdev is assigning memory regions, it should call gasp_region_set(); if this function encounters a fatal error, it terminates the running process (the qvm process instance with the vdev that called the function), which of course aborts the assembly of the VM and prevents the guest from ever running. Using gasp_region_set() during the startup stage helps minimize the chances that a guest will be loaded into a misformed VM.

Running

After the startup stage is complete, you can no longer rely on the qvm process being single-threaded. You should assume that it is multi-threaded: vdevs—including your own—may be creating new threads.

To ensure that it has exclusive access to the guest memory until it has finished assigning memory regions, your vdev must call gasp_lock() to lock the guest memory. When it has finished assigning memory regions, it must call gasp_unlock() to allow other vdevs access to memory.

To assign memory regions, depending on the behavior you want for your system, your vdev can call either gasp_region_set() or gasp_region_set_soft(), which sets errno and doesn't terminate the calling process if it encounters a fatal error.

gasp_region_set() and gasp_region_set_soft()

Behavior of the gasp_region_set*() functions is determined by the gasp_region structure's flags member; this member is a bitset of values specified by qvm_state_types (see Data elements and their types above). This bitset is used to describe memory types and other types of resources.

Memory regions may be of type QST_MEMORY (ARM and x86) or QST_X86_IO (x86 only).

QST_MEMORY

If the region referenced by a gasp_region_set*() function's rgn argument is of type QST_MEMORY, the qvm_state_block's location member specifies a guest physical address. In this case, behavior of the gasp_region_set*() functions is as follows:

Overlapping regions

If any part of the region your vdev is assigning coincides with an existing region, the new region must be entirely within the limits of the previously existing region. A new region:

If the new region coincides with an existing region, the gasp_region_set*() functions modify the existing region(s) to make room for the new region, either shortening the existing region or dividing it in two. For example, if we you try to add a region (B) that extends from 0x12000 to 0x14000 to a guest memory space that already includes a region (A) that extends from 0x10000 to 0x20000, the qvm process will create three regions:

QST_X86_IO

If the region referenced by a gasp_region_set*() function's rgn argument is of type QST_X86_IO, the qvm_state_block's location member specifies a guest I/O port number range instead of a guest-physical address range. In this case, behavior of the gasp_region_set_*() functions is as follows: