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.
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).
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:
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).
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.
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.
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).
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:
If gasp_region.flags is set to 0 (zero), all previously assigned regions inside the memory range where the function is assigning its memory region are deleted, unless the existing region's gasp_region.flags member is set to GRF_PRECIOUS (see gasp_region_flags).
If you want a region to persist, set this value in the GRF_* bitset when you create the region.
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:
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: