【问题标题】:Does simulating memory-mapped I/O using VMX require instruction decoding?使用 VMX 模拟内存映射 I/O 是否需要指令解码?
【发布时间】:2016-12-11 09:33:12
【问题描述】:

我想知道使用英特尔 VMX / VT 技术的管理程序如何模拟内存映射 I/O(这样来宾可能会认为它正在对设备执行内存映射 I/O)。

我认为基本原则是设置 EPT 页表,以使所讨论的内存地址通过将它们设置为无法读取或写入而导致 EPT 违规(即 VM 退出)?但是,下一个问题是如何处理 VM 退出。这样的 VM 退出将填写所有退出资格原因等,包括来宾线性地址和来宾物理地址等。但是我在这些退出资格字段中缺少的是一些字段,指示 - 在写入指令的情况下 -尝试写入的值和写入的大小。同样,对于读取指令,最好使用一些指示读取目的地的位字段,例如寄存器或内存位置(在内存到内存字符串操作的情况下)。这将使管理程序很容易弄清楚来宾尝试做什么,然后模拟设备对来宾的行为。

但麻烦的是,我在退出资格中找不到这样的字段。我可以看到指向错误指令所在位置的指令指针,因此我可以遍历页表以读取指令,然后对其进行解码以理解指令,然后模拟 I/O 行为。但是,这需要管理程序对所有 x86 指令有相当完整的了解,并且能够对它们进行解码。这似乎对虚拟机管理程序来说是一个相当沉重的负担,并且还需要它在以后添加指令时保持最新状态。 CPU 应该已经有了这些信息。

我可能会错过这些相关字段,因为文档非常广泛,但我尝试仔细搜索但无法找到它。也许有人可以为我指明正确的方向,或者确认管理程序需要包含指令解码器。

【问题讨论】:

  • 我误解了你的问题。不过,您可能需要查看 Intel 的 VT-d 论文,因为它涉及 IO 虚拟化
  • 如果您将那堵巨大的文字墙分成多个段落,这将显着提高可读性。
  • 有趣的标题,但不够有趣,无法涉足这个巨大的单段文字墙。
  • @Peter:如果这就是你所指的,我已经插入了一些中断。

标签: memory assembly virtualization


【解决方案1】:

我相信大多数虚拟机都会对指令进行解码。这实际上并不难,大多数虚拟机都有软件仿真器,当 CPU 虚拟机扩展不可用或无法完成任务时,它们可以回退。您不需要处理每条指令,只需要处理那些可以使用内存操作数的指令,并且您可能会忽略不是 1、2 或 4 字节内存操作数的所有指令,因为您不太可能模拟设备寄存器那些尺寸。 (对于内存映射的设备缓冲区,例如视频内存,您​​不希望捕获每个内存访问,因为这太慢了,因此您必须采取不同的方法。)

但是,有一种方法可以让 CPU 为您完成工作,但它比解码指令本身要慢得多,而且并不完全完美。您可以在临时映射到 RAM 的有效页面时单步执行指令。 VM 出口将告诉您来宾物理地址访问以及它是读取还是写入。不幸的是,它不能可靠地告诉您它是否是读-修改-写指令,这些指令可能只是设置了写标志,并且某些设备寄存器可能会有所作为。复制指令可能更容易(它最多只能是 15 个字节,但要注意页面边界)并在主机中执行它,但这要求您可以将页面映射到主机中的相同虚拟地址,如客人。

您可以结合这些技术,解码实际用于访问内存映射设备寄存器的常用指令,同时对您不认识的指令使用单步执行。

请注意,选择编写自己的虚拟机管理程序会给自己带来沉重的负担。与模拟整个 IBM PC 兼容计算机的任务相比,必须在软件中解码指令是一个相当小的负担。英特尔虚拟化扩展并非旨在让这一切变得更容易,它们只是为了提高效率而设计。编写一个解释指令的纯软件模拟器会更容易。处理内存映射 I/O 只需将读取和写入分派到正确的函数即可。

【讨论】:

  • 您好罗斯,谢谢您的回答。这也符合我所担心/期望的。我真的很想知道为什么英特尔没有实现这个功能。软件解码也必须产生开销,CPU 有一个专用的硬件解码器。这只是将一些控制信号放入 VM 寄存器的问题,它可以推广到所有指令类。我明白你关于 VMX 的观点不是为了让编写管理程序更容易(而是为了提高效率)。
  • ...但是,我确实读过一些文章,说 VMX 的第一个版本实际上比 SW 仿真器慢,但它使编写管理程序更简单。顺便说一句,就我而言,这将产生巨大的影响。我不需要虚拟化 IBM PC 的所有方面,因此 VMExit 处理程序等将是大量工作。但是,通过将完整的指令解码器(在很大程度上还有仿真器)投入其中,这会变得更加复杂。并提出了关于以后添加指令等的问题。我喜欢你关于交换页面的想法,尽管我同意这听起来像......
  • ...它可能效率低下。如果有 CPU 的帮助,它真的会干净得多。 AMD 有一个名为“解码辅助”的功能,但据我从文档中可以看出,它基本上提供了与英特尔相同的信息,它似乎没有提供我所询问的额外信息。
  • 顺便说一句,我认为一个基本上完整的解码器+仿真器(这似乎是必需的)即使与 IBM PC HW 的“有点完整”仿真(PIC+PIT+VGA +键盘等)。因为这些硬件单元陈旧且非常简单,并且为了提供实际服务,管理程序可以使用主机操作系统功能,所以它只是一个映射而不是功能的实现。而对于指令,您必须完全实现一系列前缀、编码、CPU 模式和指令集扩展以及它们的几乎所有组合。
  • @Morty 正如我所说,您不需要完整的指令解码器。只有一小部分指令实际上用于访问内存映射设备寄存器。您不必担心堆栈、FPU、SIMD 或系统指令,尤其是那些与寄存器大小不匹配的指令,因为随后发生的事情没有明确定义。如果您因为 RET、FLD、MOVSD 或 SGDT 指令访问设备内存而导致 VM 崩溃,那将是正确的做法,因为 VM 正在执行垃圾。
【解决方案2】:

我不详细了解 VT-X 的工作原理,但我认为我在您的愿望清单中看到了它的工作方式存在缺陷:

请记住,x86 不是加载/存储机器。 add [rdi], 2 的加载部分没有架构上可见的目的地,因此您提出的告诉管理程序在哪里查找或放置数据的解决方案实际上并不起作用,除非有一些临时位置这不是来宾架构状态的一部分,仅用于管理程序和 VMX 硬件之间的通信。

为了有效地处理带有内存目标的读-修改-写指令,VM 应该通过一个 VM 退出来完成整个操作。所以你不能只提供单独的加载和存储接口。

更重要的是,处理原子读取-修改-写入是一种特殊情况。 lock add [rdi], 2 不能作为单独的加载和存储来完成。

【讨论】:

  • 嗨,彼得,是的,我明白您关于读取-修改-写入的观点,因为您指出它需要 VMCS 中的一个通信字段,并且可能需要两个 VMExit。额外的 VMExit 肯定会增加开销,但解码/仿真也是如此。此外,当前的解决方案具有与 HVM 相关的开销,该开销与 HVM 必须手动 wal 来宾的页表只是为了获取指令字节,接下来必须遍历它们以获取数据值(要读取)并手动处理所有页面相关 -没有 TLB 或任何此类的表逻辑。考虑到 MMIO 的普遍性,必须为此浪费大量周期。
  • 我正在查看 KVM 中的“emulate.c”文件,这是 KVM 中似乎可以完成这项工作的文件。虽然它似乎涵盖了许多指令类型,但也有很多它没有。例如,我看不到模拟 SSE 指令的尝试。这是否意味着如果我用一个尝试使用新的闪亮的 SSE 指令进行内存映射 I/O 的驱动程序编写一个 o/s,它将无法工作?
  • @Morty:IDK,关于 KVM 中 SSE 的有趣问题。 MOVNT 存储对于写入可缓存设备内存可能很有用,因为它们会从 CPU 的缓存中驱逐数据。
  • @Morty:一些 HVM 是否会继续模拟一些指令,因为 MMIO 存储通常会成组出现?这将使他们能够将软件页面遍历的结果重用于多个 I/O 操作。就像我说的,我对 VM 的实现了解不多。我只是将其发布为答案,因为 cmets 不够大。
猜你喜欢
  • 2011-12-15
  • 1970-01-01
  • 2016-05-27
  • 1970-01-01
  • 2016-11-16
  • 2017-06-08
  • 2011-01-19
  • 2017-05-17
  • 2019-02-19
相关资源
最近更新 更多