摘要
添加内存映射。
声明
#include <zircon/syscalls.h>
zx_status_t zx_vmar_map(zx_handle_t handle,
zx_vm_option_t options,
size_t vmar_offset,
zx_handle_t vmo,
uint64_t vmo_offset,
size_t len,
zx_vaddr_t* mapped_addr);
说明
将给定的 VMO 映射到给定的虚拟内存地址区域。 该映射保留了对底层虚拟内存对象的引用,这意味着关闭 VMO 句柄不会移除此函数添加的映射。
options 是以下各项的位向量:
ZX_VM_SPECIFIC使用 vmar_offset 来放置映射,如果 handle 没有ZX_VM_CAN_MAP_SPECIFIC权限,则无效。 vmar_offset 是相对于给定 VMAR 的基地址的偏移量。 指定与另一个 VMAR 或映射重叠的范围是错误的。ZX_VM_SPECIFIC_OVERWRITE与ZX_VM_SPECIFIC相同,但可以 与另一个映射重叠。部分重叠另一个 VMAR 仍然是错误的。 如果范围满足这些要求,它将以原子方式(相对于所有 其他映射/取消映射/保护操作)替换 vmar_offset 和 len 指定的范围内的现有映射。如果该范围与任何映射部分重叠,则这些映射中超出该范围的部分将保持映射状态。ZX_VM_OFFSET_IS_UPPER_LIMIT将 vmar_offset 解释为上限 以限制内核对偏移量的选择;如果 handle 没有ZX_VM_CAN_MAP_SPECIFIC权限,则无效。生成的映射 将具有 <= vmar_base + vmar_offset 的偏移量 + len。如果使用ZX_VM_SPECIFIC或ZX_VM_SPECIFIC_OVERWRITE,则无法指定此选项 。ZX_VM_PERM_READ将 vmo 映射为可读。 如果 handle 没有ZX_VM_CAN_MAP_READ权限,或者 handle 没有ZX_RIGHT_READ权限,或者 vmo 句柄没有ZX_RIGHT_READ权限,则会出错。ZX_VM_PERM_WRITE将 vmo 映射为可写。 如果 handle 没有ZX_VM_CAN_MAP_WRITE权限,或者 handle 没有ZX_RIGHT_WRITE权限,或者 vmo 句柄没有ZX_RIGHT_WRITE权限,或者 options 未指定ZX_VM_PERM_READ,则会出错。ZX_VM_PERM_EXECUTE将 vmo 映射为可执行。 如果 handle 没有ZX_VM_CAN_MAP_EXECUTE权限,或者 handle 句柄没有ZX_RIGHT_EXECUTE权限,或者 vmo 句柄没有ZX_RIGHT_EXECUTE权限,或者 options 未指定ZX_VM_PERM_READ,则会出错。ZX_VM_MAP_RANGE立即将 VMO 的所有备份区域分页到新映射中。 如果使用ZX_VM_SPECIFIC_OVERWRITE,则无法指定此项。 如果创建的映射可能会生成故障,则需要ZX_VM_ALLOW_FAULTS。特别是,如果 vmo 可调整大小,或者设置了ZX_VM_FAULT_BEYOND_STREAM_SIZE,或者 vmo 不可调整大小但映射超出了 vmo 的末尾,或者 vmo 可舍弃,或者 vmo 是通过zx_pager_create_vmo()创建的,则需要此项。ZX_VM_PERM_READ_IF_XOM_UNSUPPORTED如果系统不支持映射仅执行页面,则将 vmo 映射为可读。如果系统可以映射仅执行,则会忽略此标志。ZX_VM_REQUIRE_NON_RESIZABLE如果 vmo 可调整大小,则失败。ZX_VM_FAULT_BEYOND_STREAM_SIZE超出流大小(向上舍入到页面边界)的内存访问将导致故障。需要ZX_VM_ALLOW_FAULTS。
如果 options 未设置 ZX_VM_SPECIFIC、
ZX_VM_SPECIFIC_OVERWRITE 或 ZX_VM_OFFSET_IS_UPPER_LIMIT,则 vmar_offset 必须为 0。
ZX_VM_OFFSET_IS_UPPER_LIMIT 用于限制选择范围,否则其行为与未设置 ZX_VM_SPECIFIC 和 ZX_VM_SPECIFIC_OVERWRITE 的情况类似,即映射由内核随机分配偏移量(分配器由目标 VMAR 上设置的政策确定)。
len 必须为非零值,并且会在内部向上舍入以与页面对齐。
此外,还可以添加以下 2 的幂对齐标志之一:
ZX_VM_ALIGN_1KB将 child_addr 与至少 1K 字节的 2 的幂对齐。ZX_VM_ALIGN_2KB将 child_addr 与至少 2K 字节的 2 的幂对齐。ZX_VM_ALIGN_4KB将 child_addr 与至少 4K 字节的 2 的幂对齐。ZX_VM_ALIGN_8KB将 child_addr 与至少 8K 字节的 2 的幂对齐。
并继续到
ZX_VM_ALIGN_4GB将 child_addr 与至少 4G 字节的 2 的幂对齐。
如果 vmar
基地址 + vmo_offset 未与请求的值对齐,则将 ZX_VM_ALIGN 标志与 ZX_VM_SPECIFIC 搭配使用将会失败。
权限
handle 的类型必须为 ZX_OBJ_TYPE_VMAR。
vmo 的类型必须为 ZX_OBJ_TYPE_VMO。
返回值
zx_vmar_map() 成功后会返回 ZX_OK 和
映射的绝对基地址(通过 mapped_addr)。基地址将与页面对齐且为非零值。 如果失败,则返回负错误值。
错误
ZX_ERR_BAD_HANDLE handle 或 vmo 不是有效的句柄。
ZX_ERR_WRONG_TYPE handle 或 vmo 分别不是 VMAR 或 VMO 句柄。
ZX_ERR_BAD_STATE handle 引用已销毁的 VMAR。
对于以下任一情况,ZX_ERR_INVALID_ARGS:
- mapped_addr 或 options 无效。
- vmar_offset 当未指定
ZX_VM_SPECIFIC、ZX_VM_SPECIFIC_OVERWRITE或ZX_VM_OFFSET_IS_UPPER_LIMIT中的任何一个时,为非零值。 - 同时指定了
ZX_VM_SPECIFIC_OVERWRITE和ZX_VM_MAP_RANGE。 - 同时指定了
ZX_VM_OFFSET_IS_UPPER_LIMIT和ZX_VM_SPECIFIC或ZX_VM_SPECIFIC_OVERWRITE。 - vmar_offset 和 len 描述的分配因超出区域边界而无法满足。
- vmar_offset 或 vmo_offset 未与页面对齐。
- len 为 0。
ZX_ERR_ALREADY_EXISTS ZX_VM_SPECIFIC 已指定,但未指定
ZX_VM_SPECIFIC_OVERWRITE,并且请求的范围与另一个映射重叠。
ZX_ERR_NO_RESOURCES 如果在 VMAR 中找不到用于创建映射的位置。
ZX_ERR_ACCESS_DENIED 权限不足,无法进行请求的映射。
ZX_ERR_NOT_SUPPORTED 如果 vmo 可调整大小、可舍弃或由分页器提供支持,但未设置 ZX_VM_ALLOW_FAULTS。
ZX_ERR_NOT_SUPPORTED 如果 vmo 可调整大小且设置了 ZX_VM_REQUIRE_NON_RESIZABLE。或者,设置了
ZX_VM_FAULT_BEYOND_STREAM_SIZE 且 vmo 是物理的或连续的。
ZX_ERR_BUFFER_TOO_SMALL VMO 不可调整大小,并且映射超出了 VMO 的末尾,但未设置 ZX_VM_ALLOW_FAULTS。
ZX_ERR_NO_MEMORY 因内存不足而失败。
用户空间没有很好的方法来处理此(不太可能发生的)错误。
在未来的版本中,此错误将不再发生。
ZX_ERR_OUT_OF_RANGE vmo_offset + ROUNDUP(len, PAGE_SIZE) 溢出。
备注
支持内存映射的 VMO 可以调整为较小的大小。这可能会导致线程读取或写入 VMAR 区域时发生故障。为避免此风险,从客户端接收
VMO 的服务在映射 VMO 时应使用 ZX_VM_REQUIRE_NON_RESIZABLE。