RFC-0128:引入 `zx_vcpu_kick`

RFC-0128:引入“zx_vcpu_kick”
状态已接受
领域
  • 内核
说明

新的系统调用“zx_vcpu_kick”,可能会导致正在运行的 vCPU 退出到主机并返回用户空间。

Gerrit 更改
作者
审核人
提交日期(年-月-日)2021 年 8 月 26 日
审核日期(年-月-日)2021-09-25

摘要

我们提议添加新的系统调用 zx_vcpu_kick,它可导致运行中的 vCPU 退出到主机并返回用户空间。此外,我们还建议重命名 将 zx_vcpu_resume 重命名为 zx_vcpu_enter,以便采用一致的命名法。

设计初衷

当一个 vCPU 正在运行时,它可能会在对 zx_vcpu_enter。这会给虚拟机管理器带来问题,因为 彻底关闭 vCPU,则虚拟机管理器需要系统调用返回 以便能够安全地释放所有相关的 资源。

此外,为了简化集成测试, 有一种方法来强制某个 vCPU 退出客户机,非常方便。如此一来, 可以更简洁、更精确地编写测试。

利益相关方

教员:CPU

审核者:adanis、tamird、jamesr

已咨询:dgreenaway、brunodalbo

社交化:我们在聊天会话中讨论了设计,这是 用于解决连接团队在使用 netemul 时遇到的问题, 测试。

设计

该方案包含对 Zircon 系统调用接口的以下更改:

  1. zx_vcpu_kick 的新增
  2. zx_vcpu_resume 已更名为 zx_vcpu_enter

其中,zx_vcpu_enterzx_vcpu_kick 将定义如下:

/// Enter a VCPU, and start or continue execution.
/// Rights: handle must be of type ZX_OBJ_TYPE_VCPU and have ZX_RIGHT_EXECUTE.
// @blocking
zx_status_t zx_vcpu_enter(
    zx_handle_t handle,
    uint32_t options,
    zx_port_packet_t* packet
);

/// Exit from the current or next call to |vcpu_enter|.
/// Rights: handle must be of type ZX_OBJ_TYPE_VCPU and have ZX_RIGHT_EXECUTE.
zx_status_t zx_vcpu_kick(
    zx_handle_t handle
);

对一个 vCPU 句柄调用 zx_vcpu_kick 时,当前正在运行的所有对 同一句柄上的 zx_vcpu_enter 将返回 ZX_ERR_CANCELED。此外, 如果在调用 zx_vcpu_kickzx_vcpu_enter 未运行,则 对 zx_vcpu_enter 的下一次调用将立即返回 ZX_ERR_CANCELED。这个 允许虚拟机管理器调用 zx_vcpu_kick,并保证 zx_vcpu_enter 接下来将返回 ZX_ERR_CANCELED。反过来,这意味着 如果 zx_vcpu_enter 尚未返回 ZX_ERR_CANCELED,则只会返回 无论 zx_vcpu_kick 调用多少次。

已选择 ZX_ERR_CANCELED 作为要返回的状态,因此是退出的原因 很容易被虚拟机管理器区分开这样, 虚拟机管理器,使用该状态正常停止 vCPU 虚拟机管理器中提供了额外的状态管理功能何时检测到 如果 zx_vcpu_enter 返回了 ZX_ERR_CANCELED,则可以关闭此 vCPU 处理和释放任何其他关联资源。

此外,zx_vcpu_kick 的行为是停止 vCPU,但不会停止 终止它。这意味着,虚拟机管理器可以恢复 通过调用 zx_vcpu_enter 后的 vCPU 返回 ZX_ERR_CANCELED zx_vcpu_enter。除了处理返回值和绕过 虚拟机管理器不需要执行任何操作 特殊,可以立即调用 zx_vcpu_enter 以继续执行。

实现

在 Hypervisor 中,zx_vcpu_enter 的建模依据是 zx_port_wait。它具有 API 几乎完全相同,只不过是截止时间。而是需要等待 然后带该数据包返回到用户空间 与 zx_thread_start 不同,它并不是为创建 执行,而不是转换当前的执行线程。

话虽如此,但我们认为基于令牌的方法 在 zx_task_suspend 中找到)对中断 vCPU 的执行很有效。答 基于词元的方法不适合 VCPU 执行模型, 常量来回传递。

我们提议 zx_vcpu_kick 直接导致 zx_vcpu_enter 返回 用户空间,并显示一个表明已中断的错误代码。在 Hypervisor,zx_vcpu_kick 的实现方式与 zx_vcpu_interrupt。它会:

  1. 设置状态。对于 zx_vcpu_kick,此状态是一个原子布尔值,用于 指示 vCPU 在退出客户机时应返回。此变量 可通过使用 zx_object_get_info 进行查询,主题为 ZX_INFO_VCPU 和相应的 zx_info_vcpu_t 类型。
  2. 检查此 vCPU 当前是否正在运行,如果是,则 IPI 为物理 CPU 当前运行的 vCPU 数量这会强制此 vCPU 退出 来宾客处理中断,从而允许其为事件提供服务 请求返回。

原子布尔值跟踪是否调用了 zx_vcpu_kick 以及 vCPU 如果不再有任何待处理的请求,则应返回 ZX_ERR_CANCELED 返回用户空间的信息这意味着,如果有未完成的 用户空间的来宾数据包,在返回之前会成功返回 在对 zx_vcpu_enter 的后续调用中调用 ZX_ERR_CANCELED

此方法使 zx_vcpu_enter 的行为类似于 zx_port_wait, 发生超时。

将在单个 CL 中进行实现,因为 Hypervisor 包含在 Fuchsia 代码库中。此次变更将包括 对系统调用的文档和语言绑定的更新,以及相关更改 虚拟机管理器角色

性能

除了导致访客退出之外,对性能没有任何已知的影响 执行。它的主要用途是正常终止 应该不会产生实际影响

工效学设计

讨论了 zx_vcpu_enterzx_vcpu_kick 的人体工学注意事项 在设计部分。

向后兼容性

Hypervisor 的所有已知用户都包含在 Fuchsia 代码库中, 因此可以引入 zx_vcpu_kick 并重命名 将zx_vcpu_resume更改为zx_vcpu_enter

安全注意事项

应对使用 zx_vcpu_kick 的虚拟机管理器进行审核,以确保 任何使用 zx_vcpu_enter 的行为都会考虑 ZX_ERR_CANCELED 返回 并且它必须忽略返回的 PortPacket(如果要 恢复操作。如果未忽略 PortPacket,则 对已清零的无效数据执行操作 - 如果任何错误都为 true, zx_vcpu_enter 返回的状态。

隐私注意事项

此方案对隐私权没有任何影响。

测试

实现 CL 上线后,我们就可以为 虚拟机管理器测试,证明我们可以在没有相关虚拟机的情况下 ASAN 故障。

文档

我们需要为 zx_vcpu_kick 系统调用添加其他文档,并且 我们需要将 zx_vcpu_enter 系统调用的文档扩展为 包括新的退货状态和 PortPacket 处理建议。

缺点、替代方案和未知问题

该方案的缺点是引入了额外的系统调用。它 最初提议我们可以重复使用 zx_task_killzx_handle_close,但两者都有自己的缺点。

如需专门将 zx_task_kill 与 vCPU 配合使用,我们必须考虑 将 vCPU 设为一项任务,从而让所有与任务相关的系统调用都适用于 vCPU。 如果我们只将 zx_task_kill 用于 vCPU,而不使用任何其他 CPU 与任务相关的系统调用,则可能是不一致的。

我们可以依赖 zx_handle_close 的语义并添加一个 on_zero_handles 处理程序添加到 VcpuDispatcher。这样,我们便可以 如果句柄计数为零,则终止 VCPU。不过,这有两个 直接缺点:vCPU 停止后便无法再恢复, 并让 vCPU 句柄失效“vCPU 句柄的失效”现为 尤其容易出现问题,因为它本身就是一种竞态操作。其他消息串 可能正在使用 vCPU 句柄进行注入和中断, 句柄无效,因此会导致意外错误。

另一种方法是引入此系统调用的更通用的版本, 示例 zx_thread_cancel,其中指定线程上的任何阻塞操作 会立即返回 ZX_ERR_CANCELED。这样,我们就可以扩展系统调用 未来使用与 vCPU 类似的模型的用例。

先验技术和参考资料

Apple 的 Hypervisor Framework 中存在类似的操作: https://developer.apple.com/documentation/hypervisor/1441468-hv_vcpu_interrupt

以及在 Linux 的 KVM(基于内核的虚拟机)中: https://www.kernel.org/doc/html/latest/virt/kvm/vcpu-requests.html#vcpu-kicks