Virtual Memory Address Region


vm_address_region - A contiguous region of a virtual memory address space


Virtual Memory Address Regions (VMARs) represent contiguous parts of a virtual address space.


VMARs are used by the kernel and userspace to represent the allocation of an address space.

Every process starts with a single VMAR (the root VMAR) that spans the entire address space (see zx_process_create()). Each VMAR can be logically divided up into any number of non-overlapping parts, each representing a child VMARs, a virtual memory mapping, or a gap. Child VMARs are created using zx_vmar_allocate(). VM mappings are created using zx_vmar_map().

VMARs have a hierarchical permission model for allowable mapping permissions. For example, the root VMAR allows read, write, and executable mapping. One could create a child VMAR that only allows read and write mappings, in which it would be illegal to create a child that allows executable mappings.

When a VMAR is created using zx_vmar_allocate(), its parent VMAR retains a reference to it. Because of this, if all handles to the child VMAR are closed, the child and its descendants will remain active in the address space. In order to disconnect the child from the address space, zx_vmar_destroy() must be called on a handle to the child.

By default, all allocations of address space are randomized. At VMAR creation time, the caller can choose which randomization algorithm is used. The default allocator attempts to spread allocations widely across the full width of the VMAR. The alternate allocator, selected with ZX_VM_COMPACT, attempts to keep allocations close together within the VMAR, but at a random location within the range. It is recommended to use the default allocator.

VMARs optionally support a fixed-offset mapping mode (called specific mapping). This mode can be used to create guard pages or ensure the relative locations of mappings. Each VMAR may have the ZX_VM_CAN_MAP_SPECIFIC permission, regardless of whether or not its parent VMAR had that permission.


#include <zircon/syscalls.h>

/* Map this VMO into the given VMAR, with |before| bytes of unmapped guard space
   before it and |after| bytes after it.  */
zx_status_t map_with_guard(zx_handle_t vmar, size_t before, size_t after,
                           zx_handle_t vmo, uint64_t vmo_offset,
                           size_t mapping_len, uintptr_t* mapped_addr,
                           zx_handle_t* wrapping_vmar) {

    /* wrap around check elided */
    const size_t child_vmar_size = before + after + mapping_len;
    const zx_vm_option_t child_vmar_options = ZX_VM_CAN_MAP_READ |
                                              ZX_VM_CAN_MAP_WRITE |
    const zx_vm_option_t mapping_options = ZX_VM_SPECIFIC |
                                           ZX_VM_PERM_READ |

    uintptr_t child_vmar_addr;
    zx_handle_t child_vmar;
    zx_status_t status = zx_vmar_allocate(vmar, child_vmar_options, 0,
    if (status != ZX_OK) {
        return status;

    status = zx_vmar_map(child_vmar, mapping_options, before, vmo, vmo_offset,
                         mapping_len, mapped_addr);
    if (status != ZX_OK) {
        return status;

    *wrapping_vmar = child_vmar;
    return ZX_OK;