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 系统调用接口的以下更改:
- 添加了
zx_vcpu_kick
- 将
zx_vcpu_resume
重命名为zx_vcpu_enter
其中,zx_vcpu_enter
和 zx_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_enter
在调用 zx_vcpu_kick
时未运行,则对 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
在 zx_vcpu_enter
返回 ZX_ERR_CANCELED
后恢复 VCPU 的执行。除了处理返回值并绕过任何数据包处理外,虚拟机管理器不需要执行任何特殊操作,并且可以立即调用 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_interrupt
非常相似。zx_vcpu_kick
此功能将会:
- 设置状态。对于
zx_vcpu_kick
,此状态是一个原子布尔值,用于指示 VCPU 在退出客户机时应返回。此变量可通过主题为ZX_INFO_VCPU
和相应的zx_info_vcpu_t
类型的zx_object_get_info
进行查询。 - 检查 vCPU 当前是否正在运行;如果是,则 IP 地址是 vCPU 当前正在运行的物理 CPU。这会强制 VCPU 退出客户机以处理中断,从而允许其处理要返回的请求。
原子 bool 会跟踪是否已调用 zx_vcpu_kick
,以及当 VCPU 不再具有要返回用户空间的任何未完成信息时,应返回 ZX_ERR_CANCELED
。这意味着,如果存在针对用户空间的未完成来宾数据包,则会先成功返回该数据包,然后我们再在后续调用 zx_vcpu_enter
时返回 ZX_ERR_CANCELED
。
这种方法使 zx_vcpu_enter
的行为类似于遇到超时的 zx_port_wait
。
该实现将在单个 CL 中执行,因为 Hypervisor 的所有已知用户都包含在 Fuchsia 代码库中。此变更将包括对系统调用的文档和语言绑定的更新,以及对 Hypervisor 和虚拟机管理器的更改。
性能
除了导致客户机退出执行之外,对性能没有已知的影响。由于这样做的主要用例是正常终止 VCPU 的执行,因此应该不会产生实际影响。
工效学设计
设计部分讨论了 zx_vcpu_enter
和 zx_vcpu_kick
的人体工程学注意事项。
向后兼容性
Hypervisor 的所有已知用户都包含在 Fuchsia 代码库中,因此引入 zx_vcpu_kick
并将 zx_vcpu_resume
重命名为 zx_vcpu_enter
是可行的。
安全注意事项
应审核使用 zx_vcpu_kick
的虚拟机管理器,以确保对 zx_vcpu_enter
的任何使用均考虑 ZX_ERR_CANCELED
返回状态,并且如果它打算恢复 VCPU 的操作,则必须忽略返回的 PortPacket
。如果不忽略 PortPacket
,则它将对已归零的无效数据进行操作(对于 zx_vcpu_enter
返回的任何错误状态而言,该值为 true)。
隐私注意事项
此方案对隐私权没有任何影响。
测试
实现 CL 发布后,我们就可以为虚拟机管理器测试启用 ASAN 聊天机器人,并证明我们可以彻底关闭而不会发生 ASAN 故障。
文档
我们需要为 zx_vcpu_kick
系统调用添加额外的文档,还需要扩展 zx_vcpu_enter
系统调用的文档,以包含新的返回状态和 PortPacket
处理建议。
缺点、替代方案和未知情况
此方案的缺点是引入了额外的系统调用。最初提议可以重复使用 zx_task_kill
或 zx_handle_close
,但两者都有自己的缺点。
为了让 zx_task_kill
专门用于 VCPU,我们必须将 VCPU 视为一项任务,从而使所有与任务相关的系统调用都能与 VCPU 配合使用。如果我们只将 zx_task_kill
用于 VCPU,而没有其他与任务相关的系统调用,就会产生不一致。
我们可以改为依赖 zx_handle_close
的语义,并向 VcpuDispatcher
添加 on_zero_handles
处理程序。这样一来,我们就可以在句柄计数降至零时终止 VCPU。不过,这样做有两个直接的缺点:当 VCPU 停止后,我们无法再将其恢复,并且会让 VCPU 句柄失效。VCPU 句柄的失效特别存在问题,因为它本身是一种竞态操作。当句柄失效时,另一个线程可能正在使用 VCPU 句柄进行注入和中断,从而导致意外错误。
另一种方法是引入此系统调用的更通用版本,例如 zx_thread_cancel
,其中针对指定线程的任何阻塞操作会立即返回 ZX_ERR_CANCELED
。这样一来,我们就可以将系统调用扩展到未来使用与 VCPU 类似模型的用例。
早期技术和参考资料
Apple 的 Hypervisor Framework 中存在类似的操作:https://developer.apple.com/documentation/hypervisor/1441468-hv_vcpu_processor
以及 Linux 的 KVM(基于内核的虚拟机):https://www.kernel.org/doc/html/latest/virt/kvm/vcpu-requests.html#vcpu-kicks