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 the functions, data
structures, etc. discussed here.
Data elements and their types
The qvm_state_block data structure describes a data element in a guest. The type of element is represented by the qst_type member of this structure. For example, with qst_type set to QST_MEMORY, the qvm_state_block location member is a guest-physical address, while with a qst_type of QST_PCI, location 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 to on the host system (i.e., its host-virtual address), and where it should appear in the guest. This structure's guest member is a qvm_state_block structure whose location member refers to the resource type.
- the qst_type field in the contained qvm_state_block object — this should be set to the QST_* value for the type of resource you need
- the qst_flags field (also in the qvm_state_block object) — this should contain the QSF_* constants for the required qvm state settings
- the grf_flags field of the gasp_region object — this should contain the GRF_* constants to define the desired access behavior (e.g., read/write/execute) and address space characteristics (e.g., whether the region is installed)
Assigning memory regions
Use the gasp_*() functions to assign a memory region with the characteristics specified in the gasp_region data structure.
Your vdev can assign itself memory for its own use. There are some important differences in how the vdev should assign itself memory during the qvm process instance's startup stage versus after this 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. For more information, see
Lifecycle of a vdev
in this chapter, and
vdtrace_control() in
The Basics: vdev trace
chapter.
Assigning memory after startup
After the startup stage is complete, you can no longer rely on the qvm process being single-threaded. You should assume that it is multithreaded: vdevs—including your own—may be creating new threads.
You can assign memory regions as follows:
- Call gasp_lock() to lock the guest address space to ensure that no other vdev can claim the region you need before you finish your task.
- Call gasp_find_free() or gasp_find_free_range() to find available memory of the QST_* type you specify.
- Call gasp_region_set() or gasp_region_set_soft() to assign the memory region. Which of these functions you will use depends on the behavior you want for your system. For the first function, if it encounters a fatal error, it terminates the running process (i.e., the qvm process with the vdev that called the function). The second function sets errno but does not terminate the running process if it encounters a fatal error.
- Call gasp_unlock() to unlock the guest address space and make unassigned regions available to other vdevs.
Assigning memory during 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 address space before you can call other gasp_*() functions to find and assign guest memory regions. You also don't need to call gasp_unlock() to release the remainder of the guest memory when you have finished assigning memory for your vdev. Thus, you can skip steps one and four in the memory assignment procedure described in the previous section.
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, 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 malformed VM.
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 QST_* values
(see Data elements and their types
above) and is used to
describe memory and other resource types.
Memory regions may be of type QST_MEMORY (ARM and x86) or QST_X86_IO (x86 only).
QST_MEMORY
If the region referenced by the structure given in a gasp_region_set*() function's rgn argument is of type QST_MEMORY, the qvm_state_block structure's location member specifies a guest-physical address. In this case, behavior of the gasp_region_set*() function is as follows:
- If the gasp_region structure's flags field 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 flags member has the GRF_PRECIOUS bit set (see the GRF_* constants). If you want a region to persist, set this bit in the flags field when you create the region.
- If the region your vdev is assigning doesn't coincide with existing regions, the function simply adds the new region to the guest's address space.
- If the region your vdev is assigning coincides with an existing region, the function modifies the existing region to include the new one (see the next section).
Overlapping memory regions
- may not extend beyond the boundaries of an existing region
- may not straddle multiple regions
- must be compatible with the coinciding region
The gasp_region_set*() functions modify the existing region to make room for the new region, either shortening the existing region or dividing it as needed. For example, if 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:
- A — 0x10000 to 0x11FFF
- B — 0x12000 to 0x14000
- C — 0x14001 to 0x20000
QST_X86_IO
If the region referenced by the structure given in a gasp_region_set*() function's rgn argument is of type QST_X86_IO, the qvm_state_block structure'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_*() function is as follows:
- If you don't set any of the GRF_PASS_* or GRF_VIRT_* bits for gasp_region structure's flags field, the qvm process deletes the region.
- The region location plus the region length (specified in the qvm_state_block structure's location and length fields) may not extend beyond 64K bytes.
- If you set one of GRF_PASS_RD or GRF_PASS_WR, you must set both.
- If you set both GRF_PASS_RD and GRF_PASS_WR, the host location must be equal to the guest location; that is, the gasp_region structure's host_location field must equal the structure's guest.location field (where guest is the contained qvm_state_block object).
