完全仿真与完全虚拟化

44

在完全仿真中,I/O设备、CPU和主存储器都是虚拟化的。客户操作系统将访问虚拟设备而不是物理设备。但是什么是完全虚拟化?它与完全仿真是相同的还是完全不同的东西?

在完全虚拟化中,虚拟机会虚拟化所有的硬件,包括CPU、内存和I/O设备。客户操作系统只能访问虚拟设备,而无法直接访问物理设备。与之相反,在完全仿真中,所有的硬件都被模拟出来,包括CPU、内存和I/O设备。客户操作系统访问的是模拟的硬件,而非真实的硬件。因此,完全虚拟化和完全仿真是两个不同的概念。
9个回答

46

仿真和虚拟化是相关但并不相同的。

仿真使用软件提供不同的执行环境或体系结构。例如,您可能在Windows计算机上运行Android模拟器。由于Windows计算机没有与Android设备相同的处理器,因此模拟器实际上通过软件执行Android应用程序。

虚拟化更多地关注在同一物理环境中创建多个虚拟环境之间的虚拟隔离。最大的区别是虚拟化环境具有相同的体系结构。虚拟化应用程序可能提供虚拟设备,然后将其转换为物理设备,并且虚拟化主机可以控制每个虚拟机对每个设备或设备部分的访问权限。实际的执行通常仍然是本地执行,而不是通过软件执行。因此,虚拟化性能通常比仿真好得多。

还有一个独立的概念,即虚拟机,例如运行Java、.NET或Flash代码的虚拟机。它们可能因实现而异,并可能包括仿真或虚拟化或两者兼而有之的方面。例如,JVM提供了一种执行Java字节码的机制。但是,JVM规范并不规定字节码必须由软件执行或必须编译为本机代码。每个JVM都可以做自己的事情,实际上大多数JVM在适当的情况下都使用仿真和JIT的组合(我认为Sun / Oracle的JVM称之为Hotspot JIT)。


在VMware中,虚拟客户机显示的CPU与主机相同,但其他设备与主机不同。这是否意味着CPU被虚拟化而其他设备被模拟? - user44444444
2
@use736468,即使它们不是1:1的显示,它们仍然可以被虚拟化而不是模拟。例如,在VMWare中,您可以拥有一个虚拟的CD驱动器,它连接到真实的物理CD驱动器,或者您可以拥有一个由主机上的ISO映像支持的模拟CD驱动器。您还会遇到理论差异与实际差异的问题。除了纯模拟器(如Android模拟器或那些旧的8位NES模拟器(我最喜欢!)),大多数产品实际上都包含一些虚拟化和模拟的组合。 - Samuel Neff
我认为这个论点有点循环。例如,听起来像是Wine是一个在Linux上模拟Windows的虚拟化平台。使用CPU硬件来管理多个操作系统而不需要para-virtualization的超级监视器是虚拟化。在Windows PC上的GBA模拟器是一个模拟器。其他所有东西可能都是混合体。我认为你的评论更加到位。+1尝试做不可能的事情。 - artless noise
你说模拟器也会模拟CPU,而虚拟机则不会,但正如user4所指出的,Virtualbox或vmware提到了虚拟机的CPU,你可以指定它有多少个核心。那么这仍然可能是模拟CPU吗?如果你说被模拟/虚拟的CPU必须是不同的架构才能称之为模拟,那么这些定义听起来相当武断,此外,我想问一下dosbox,一个模拟x86 CPU的模拟器。主机可能是一个x86 CPU。 - barlop

10

enter image description here

虚拟机监控器(Hypervisor)是指督导其他督导者的督导者,即它是控制内核的内核。

第一类、第二类和混合型虚拟机监控器

  • 第一类虚拟机监控器是一种专门用于运行虚拟机(VMs)的操作系统。它直接安装在磁盘上以从引导扇区执行,像任何操作系统一样;它是一个为管理和运行虚拟机而构建的操作系统,并且你只能在其上运行虚拟机(就像操作系统一样,它可以是单体或微内核化)。在其中安装的所有操作系统都作为客户机运行。
  • 第二类虚拟机监控器是运行在设计为运行应用程序的操作系统之上的虚拟机监控器,可以作为应用程序运行(全面仿真),或通过修改内核并添加驱动程序来赋予操作系统运行虚拟机的功能(虚拟化)。它在主机操作系统下面/旁边被隐形地安装,并且主机操作系统继续运行(在软件虚拟化和不支持VMX模式的驱动程序下是在环0中,而在硬件虚拟化的情况下是在VMX非根模式下),其下挂钩的监控器以VMX非根模式(在硬件虚拟化的情况下)或环1(在软件虚拟化的情况下)管理客户机,并在合适时传递到主机操作系统并调用它的驱动程序来访问硬件(这就是为什么它经常被描绘为在主机操作系统之上)。主机操作系统上的图形用户界面与驱动程序通信,并且每个VM都有一个子进程和每个虚拟CPU线程。
  • 混合型虚拟机监控器是设计用于运行应用程序和虚拟机的操作系统。它可以在常规主机操作系统模式下运行,但它具有虚拟机监控器模式,当引导并加载主机操作系统作为客户机时,它在虚拟机监控器之上运行,并且可以加载其他客户机。监控器通常是微内核化监控器,这意味着硬件驱动程序在主机操作系统(称为父分区)中实现,而不是在监控器中实现(在Hyper-V上,集成服务组件驱动程序可以安装在其他客户机上,以通过主机操作系统设置的VMBUS系统与主机操作系统驱动程序通信)。主机操作系统在VMX非根模式下运行,并具有VMCS。理论上,您可以获得半虚拟化的混合型虚拟机监控器,但是KVM和Hyper-V仅支持硬件虚拟化。此外,还可以使用单体混合型虚拟机监控器,但这没有多少意义,并且由于存在主机操作系统,因此它只需要微内核化。混合型虚拟机监控器本质上是一种可以以第一类虚拟机监控器模式和主机操作系统模式分别引导的第一类虚拟机
    完全模拟器将目标ISA的所有寄存器作为变量进行模拟,CPU也将完全模拟。这可能是因为想要模拟一个ISA与主机不同的客户端(如果您运行x86模拟器例如Bochs,并且您恰好在x86系统上运行它,则可以是相同的;这不重要),因为所有解释和仿真都在进程本地完成,并且进程调用常规主机I/O函数,因此模拟器不需要特权访问(ring 0 driver helper)。这能够正常工作,因为没有任何代码需要本地运行。如果您希望它本地运行,则必须通过驱动程序将此功能带入到ring 0中。完全模拟是一种模拟所有内容的方法:CPU,芯片组,BIOS,设备,中断,页面行走硬件,TLB。模拟器进程在ring 3中运行,但对客户端来说不可见,客户端看到的是模拟/虚拟环(0和3),这将由解释器监视,并通过根据其正在解释的指令为寄存器变量分配值来模拟中断,模仿CPU在每个阶段所做的操作,但以软件形式进行。模拟器从地址中读取指令,对其进行分析,并且每次寄存器(例如EDX)出现时,它都将读取EDX变量(仿真EDX)。它模拟了CPU的操作,这是缓慢的,因为单个操作通常会由CPU透明地处理多个操作。如果客户端试图访问虚拟地址,则动态重新编译器将获取此客户端虚拟地址,并使用vCR3来遍历客户端页表(模仿TLB未命中页行走器),然后使用仿真器进程页表从vCR3+客户端虚拟地址部分产生的每个物理地址直接读取,其cr3无法控制,因为它是一个进程,并且根据主机OS的看法,物理地址只是进程中的虚拟地址(客户端物理映射到宿主机虚拟地址,通过添加偏移量然后像宿主机虚拟地址一样操作,因此有一个隐式的P2M表)。如果动态重新编译器在使用vCR3遍历过程中检测到客户端PTE上的无效位,则将地址放入vCR2中模拟给客户端造成页面故障。
    软件虚拟化类型2虚拟化程序可以实际用于类型2虚拟化程序,并且是从前一种方式中性能提升的一种方法,只有当客户端ISA与宿主机ISA相同时才能使用。在x86上无法实现完全虚拟化,因为:
    在x86架构中,实现环1存在某些缺陷从未得到修复。某些应在环1中触发的指令却没有触发。例如,LGDT/SGDT、LIDT/SIDT或POPF/PUSHF指令对此产生影响。虽然“载入”操作是特权的,因此可以被捕获,但“存储”指令总是成功的。如果允许客户机执行这些操作,它将看到CPU的真实状态,而不是虚拟化状态。CPUID指令也存在同样的问题。
    实际上,这也适用于环3。这不仅仅是环1的一个小故障。SGDT等不是特权指令,但允许VM执行它违反了Popek和Goldberg的要求,因为VM可以读取CPU的真实状态并获取真实GDT的地址,而不是虚拟的。在UMIP之前,x86上无法进行完全软件虚拟化,在英特尔VT之前,x86处理器本质上不符合Popek和Goldberg的要求,因此必须使用部分虚拟化。虽然部分虚拟化仍然不符合Popek和Goldberg(因为只有内核模式代码被修补,所以可以使用SGDT),但至少它有效,而完全虚拟化根本不起作用,因为SGDT将在客户机内核模式中读取虚假值(主机SGDT),这意味着如果未修补,则使用SGDT的客户机内核代码将无法按预期工作。SGDT在用户模式下可用至少不会危及主机操作系统,而LGDT则肯定会。
    VirtualBox使用环1完全虚拟化,但是对于那些行为像在环0中执行而实际上在环1中的有问题的指令进行了部分虚拟化,并需要一个环0驱动程序的帮助;该驱动程序充当超级管理程序。令人惊讶的是,关于如何实现类型2超级管理程序的信息非常少。以下是我对此的最佳猜测——如果是我,我将如何在给定硬件和主机操作系统运行情况下实现类型2超级管理程序。
    在Windows上,我想当驱动程序启动时,它将初始化符号链接并等待用户模式VirtualBox软件使用DeviceIoControl发出IOCTL以启动虚拟机实例。处理程序将执行以下过程:驱动程序将一个处理程序注入通用保护故障中断表(IDT)。它可以通过在IDT中替换KiInterruptTemplate来将包装器放置在KiInterruptDispatch周围从而完成此操作。在Windows中,它可以向所有IDT条目(包括bug check条目)注入一个包装器,但这意味着钩入新中断的IDT写入例程。为了实现这一点,它可能会读取IDTR中的虚拟地址并写入保护该区域,然后主机更新IDT将陷入超级管理程序GPF包装器,它将在被写入的IDT条目上安装一个包装器。
    然而,在64位Windows主机上的64位Windows客户端需要能够拥有自己的内核空间,但问题是,它将恰好位于主机内核结构的相同位置。因此,驱动程序需要清除虚拟Box进程的整个内核视图。这不能在客户端中映射或显示。它通过从虚拟盒子进程的cr3页面中删除条目来实现。虚拟盒子进程和其他主机进程使用的GDT和IDT需要相同,但为了避免保留客户端虚拟地址,当客户端写入IDTR时,hypervisor可以将其用作实际IDTR值,但在SPT中将其虚拟映射到主机使用的相同物理4KiB IDT帧。这意味着当在客户端和主机线程之间切换时,hypervisor驱动程序需要更改IDTR。由于映射IDT的客户端虚拟页面受到写保护,因此任何客户端对此范围的写操作都将被Hypervisor记录在其建立的客户端IDT中,如果cr3是其客户端进程之一。问题在于ISR处理时,它将跳转到未映射到进程中的Hypervisor RIP,因为驱动程序位于主机内核中。因此,此包装器的RIP需要映射到SPT中。这意味着您不能在客户端中保留虚拟内存,因此由于这个原因,您可能可以逃脱保留主机用于其IDT的4KiB地址范围,并将客户端访问静默重定向到不同的主机物理页面,然后无需在任务切换时更改IDTR。主机IDT中处理程序的所有保留内存也必须静默重定向到不同的主机物理页面(因为它们将是supervisor页面,所以它们将自动故障,Hypervisor只会将读写重定向到不同的主机物理页面,在中断之后不会发生这种情况,因为它将在ring 0中,所以IDT中的跳转将在映射到它的真实主机物理页面中进行映射,因为它不GPF,所以hypervisor无法重定向)因此,客户端不知道该区域已被保留。每个IDT条目都将有一个不同的包装器,它将调用一个需要映射并传递IDT条目代码的主处理程序。该处理程序将在寄存器中传递cr3,将cr3更改为映射主机内核的虚拟进程,然后将调用主处理程序。处理程序检查cr3,如果是guests shadow cr3或host cr3,则执行适当的操作。
    驱动程序还必须以同样的方式注入时钟中断--如果时钟中断触发,则推送客户机状态或主机状态(其中包括当前cr3),并且超级监控程序处理程序将在更改为映射主机内核的cr3之后,在管理它所管理的所有vCPU线程的内核堆栈上推送guest IDT时钟中断地址(模拟CPU将要做的事情)中的一个新的陷阱帧,如果不存在已经存在的情况,并在调用原始主机处理程序后。这将确保每次在主机上安排时,在客户机中进行上下文切换,因此,客户机时钟间隔将与主机时钟间隔大致匹配。
    完全虚拟化将被称为“陷阱和模拟”,但它不是全部仿真,因为所有环 3代码实际上都在主机CPU上运行(与全仿真相反,在全仿真中运行的代码是获取要读取的行的解释器)。 此外,TLB和页行走硬件实际上直接使用,而在仿真器上,如果在软件中未出现在仿真的TLB数组中,则每个内存访问都需要在软件中进行行走。 对于嘉宾,仅对特权指令和寄存器,中断,设备和BIOS进行仿真 --部分仿真--仍然发生仿真,但当任何量的代码本地运行时,就成为虚拟化(全,para或硬件辅助)。
    当客户陷入客户操作系统时,它将使用INT 0x2e或syscall。显然,hypervisor已经在0x2e处注入了一个包装器,用于INT,并且它将在 SYSENTER_CS_MSR:SYSENTER_EIP_MSR 中插入处理程序以用于sysenter或者在 IA32_LSTAR MSR中插入处理程序以用于syscall。 MSR中的处理程序需要映射到SPT中,并检查cr3是否为其中一个客户进程的shadow,如果不是,则无需更改cr3,因为当前内容将包含主机内核,并跳转到主机处理程序。如果是一个客户进程的cr3,则将其更改为虚拟盒子主机进程(可能专门用于IO任务的),并跳转到主处理程序,将RIP传递给它构建的重编译器/修补程序,后者通过paravirtualizes某些不保证会捕获的指令,将其永久替换为跳转到hypervisor内存中放置更好代码的指令(由于它们在SPT中属于ring 0,因此会导致保护故障),直到达到IRET或sysexit等指令,然后将cr3切换回客户的cr3,并在将ring 1特权放入堆栈中向它构建的guest IDT的RIP执行IRET后,实际的guest ISR才会执行。当由于在ring 1中执行ring 0指令或插入的paravirtualized陷阱而引发陷阱时,注入到通用保护故障入口/ hypervisor ISR的ISR将确保cr3是客户进程的,然后它将声明并处理问题。如果不是,则cr3无需更改为包含主机内核的一个,以便将控制权传递给主机处理程序,因为它将处于非客户进程的上下文中。这可能发生的一个示例是guest写入cr3以进行guest上下文切换。这需要进行仿真,因为guest不能执行此指令并修改cr3,因为这将更改主机操作系统上主机进程的cr3; hypervisor需要截获写入并写入新的shadow cr3而不是guest想要的cr3。当guest读取cr3时,此机制会防止guest读取真实的cr3,并且hypervisor会将guest插入的cr3值(而不是shadow值)插入所请求的寄存器中,在堆栈中插入下一个指令地址,并使用iret恢复执行并返回到相应的ring中。

    客户机I/O将针对映射到在虚拟缓冲区和模拟设备注册表中定义的客户机物理地址空间。这些模拟的寄存器(例如门铃寄存器)将以与设备响应硬件寄存器更改相同的方式在主机上下文中定期检查,处理程序将决定是否需要模拟中断(将中断推入表示所选vCPU的线程的内核堆栈以基于MSI向量由客户在模拟配置空间中分配)或者由于模拟寄存器写入,需要使用本机Windows API函数构建I/O操作,以访问客户指定的缓冲区(将GVA->HPA翻译并允许真实硬件写入客户缓冲区将使用的物理页面)。

    关于在虚拟化的64位类型2超级监控程序上进行分页,这是一个棘手的问题。硬件使用一个影子页表(SPT),将GVA映射到HPA。我最好的猜测是,超级监控程序驱动程序为每个GP故障(在第1环执行第0环指令)选择一个来自virtualbox进程的锁定页面的影子cr3页面,当它看到新的客户分配的cr3地址被写入cr3时。它将此客户选择的地址与超级监控程序选择的影子cr3页面的地址配对,并更改virtualbox进程的cr3为影子cr3而不是尝试写入的客户cr3。 内核驱动程序通过递归PML4项中的读/写位将某些GPA的cr3页面保护为只读(以防止写入), 该 影子cr3页面(您将在 everywhere 中看到写保护的客户页表,但这肯定是错误的,因为在CPU上运行的是影子页表,因此只有影子页表才能引起保护故障; 使用影子cr3而不是客户端cr3),然后,客户尝试使用的特定GPA的cr3页面将由超级监控程序转换为其关联的HPA,并且cr3页面中的条目将复制到影子cr3中,PML4E中的GPA地址将使用P2M表将转换为HPA。每次客户端尝试通过虚拟地址将此写入客户端cr3页面时,此虚拟地址将始终是影子cr3页面而不是客户端cr3页面,并且由于写入保护位和在第1环中,它将导致故障。然后,在产生一般保护故障时注入的处理程序将查看其客户进程之一的影子cr3,并在与其实际发生保护故障的位置相同的SPT中执行概念上尝试在客户PTE中执行的写操作,并插入主机物理地址而不是尝试写入的客户物理地址(使用P2M TLB或P2M进行转换;我认为P2M在启动VM时填充,因为VirtualBox进程使用 VirtualLock 锁定指定量的RAM用于虚拟机)(超级监控程序可以维护P2M的虚拟TLB(从guest frame到host frame的映射)和客户页表(从guest virtual page到guest frame的映射),在执行软件页行走之前可以检查它们,而硬件维护SPT的TLB)。然后,超级监控程序将检查虚拟TLB以快速将CR2 GVA转换为GPA;如果不存在,则它将通过访问其HVA(使用P2M将GPA->HPA然后HPA->HVA的内核函数进行转换)来跟踪客户页表,并按照客户端所需的方式写入条目。当发生页面故障时,处理程序检查影子cr3是否属于其客户进程之一,并检查SPT(使用Windows内核函数获取与故障GVA相关联的条目的虚拟地址,就像它是一个常规进程一样),然后使用与当前cr3关联的客户cr3遍历客户页表,解析引起故障的SPT虚拟地址(将GPA -> HPA -> HVA进行转换)。如果影子P

    硬件辅助型2级超级监控程序

    硬件辅助型2级超级监控程序是性能的进一步提升,将情况变得不那么复杂,并将其统一为单个接口,并自动化许多需要临时CR3跳转和管理任务的操作,使其更加清晰。内核驱动程序只需要执行vmxon,等待客户端向驱动程序注册,然后所有VM退出事件都将由插入到VMCS主机状态中的RIP和CR3的统一处理程序处理(这意味着处理程序存根不需要映射到客户机内核虚拟地址空间中)。它是专门为此设计的,不像ring 1,因此不需要重新编译器(代码扫描和分析管理器(CSAM)和补丁管理器(PATM))。它还具有TSC缩放和TSC偏移字段之类的东西,可以供使用TSC进行公平调度的客户端使用。超级监控程序仍然钩取时钟中断以执行I/O更新,并且如果当前正在执行的线程是其vCPUs之一的线程的地址,则需要vxmoff(这将引起VM退出),并将一些重新初始化序列的地址推入主机内核内存中,该序列将vmxon和vmresume与具有其中保存的客户端保存状态的VMCS绑定的vCPU(但是具有已准备执行的模拟时钟中断,其代码将使用RDTSC,该时钟中断将VM退出,并且VMCS中的偏移量可以由超级监控程序用于报告经过时间来计算客户端未在主机上调度的值,即从中减去主机时间以使主机不可见)。它不需要更改cr3,因为vmxoff会自动执行此操作,因此现在可以将其传递给主机处理程序以执行主机操作系统的时钟中断处理过程。

    如果支持EPT,则客户端选择的物理地址(cr3、IDTR等)和页表在vmx非根模式下运行的实际硬件上。GVAs翻译为HPAs的方法如下:使用客户端CR3产生PDPT的GPA,然后通过整个EPT运行使用客户端的EPTP最终获得PDPT的HPA等等(这与软件虚拟化的客户端页表和P2M相同,只是页面步进在实际的页面步进硬件上完成,速度更快)。当发生页面错误时,不会发生vm退出,并且客户端选择的IDTR存在,因此使用客户端IDT作为非根ring 0处理中断。客户端可以更新此映射,超级监控程序无需干预。在重新尝试访问时,EPT故障将导致VM退出,并具有与cr2等效的EPTP和指向客户端的监控程序EPTP的指针。然后它将更新其映射并VMRESUME到出现故障的指令的RIP。


7
在完全仿真中,I/O设备、CPU和主存储器都是虚拟化的。
不,它们是通过软件进行仿真的。仿真意味着它们的行为完全复制在软件中。
但是什么是完全虚拟化呢?
通过虚拟化,您尝试在硬件上运行尽可能多的代码以加速进程。这对于必须在内核模式下运行的代码尤其成问题,因为这可能会改变主机的全局状态(即运行Hypervisor或VMM的机器),从而影响其他虚拟机。

哦,真的吗。所以仿真和虚拟化是两个不同的概念? - user44444444
2
请参考以下链接以了解仿真和虚拟化的区别:http://www.computerworld.com/s/article/338993/Emulation_or_Virtualization_ - Jacob
1
来自ComputerWorld:虚拟化是一个应用于许多不同技术领域的流行词:服务器、存储、通信、网络。一个更老的、看似相关的术语是仿真,但它并不是同一回事。在这里,我们将梳理出它们之间的区别。如果这只是一个流行词,那么没有人能够明确地回答这个问题。 - artless noise

5

没有仿真或虚拟化,代码直接在硬件上运行。其指令由CPU本地执行,其I/O访问直接访问硬件。


虚拟化是指客户端代码至少有一部分时间在本地运行,并且只对特权操作或I/O访问(例如hypervisor)陷阱到运行在虚拟机外的主机代码。为了处理这些陷阱(也称为VM退出),虚拟机实际上可能会模拟客户端想要执行的操作。例如,客户端可能正在运行一个简单网络卡的设备驱动程序,但是NIC在虚拟机中完全由软件实现。如果虚拟机使用传递方式将客户端的I/O访问发送到主机上的真实网络卡,那么就是该硬件的虚拟化。(特别是如果它以一种让多个客户端同时使用它的方式进行,否则它实际上只是把它给了一个客户端,而不是虚拟化它。)
硬件支持虚拟化(例如英特尔和AMD的单独x86虚拟化扩展)可以让客户端执行通常会影响整个机器的操作,例如修改页面表中的内存映射。因此,CPU只需内置额外的翻译层,而不是触发VM退出并使VM弄清楚客户端正在做什么,然后从外部修改以达到结果。请参见链接的维基文章,了解基于软件的虚拟化与硬件辅助虚拟化之间更好但更长的描述。
纯模拟意味着客户机代码从未在本地运行,也从未看到主机的“真实”硬件。 模拟器不需要特权访问主机。 (有些人可能希望获得特权访问主机以进行设备透传,或者使用原始网络套接字使客户机看起来像真正连接到主机上的网络一样)。
在x86主机上运行的ARM模拟器总是必须这样工作,因为主机硬件不能首先运行ARM指令。
但是,您仍然可以在x86主机上模拟x86客户机,例如。 客户机和主机体系结构匹配并不意味着模拟器必须利用这一点。
例如,BOCHS是一个使用可移植C++编写的x86 PC模拟器。其主要用途之一是用于调试引导加载程序和操作系统。
BOCHS不在意它是否在x86主机上运行。它只是一个读取二进制文件(磁盘映像)并在窗口中绘制(客户机视频内存内容)的C++程序。就主机而言,它与JPG查看器或游戏并没有特别不同。
一些模拟器使用二进制翻译将客户代码JIT编译为主机代码,但这仍然是模拟,而不是虚拟化。请参见http://wiki.osdev.org/Emulator_Comparison

BOCHS比较慢,因为它直接读取和解码客户指令,而不进行二进制翻译。但它尽可能地高效运行。请参阅How Bochs Works Under the Hood以了解它使用的一些技巧来有效地跟踪客户状态。由于仿真是在非x86硬件上运行x86软件的唯一选择,因此拥有高性能仿真器非常有用。BOCHS有一些非常聪明和经验丰富的仿真器开发人员在开发中,特别是Darek Mihocka,在他的网站上有一些有趣的文章on his site关于优化仿真。


我注意到一些启动加载代码,例如“mov ax,[addr]”,在VMware Player上执行时与真实机器上的行为不同...是否有好的参考资料(URL /研究论文)来解释这些差异? - vtd-xml-author
@vtd-xml-author:架构是相同的,不同之处在于BIOS以及它在跳转到引导加载程序代码之前如何设置寄存器(包括段寄存器)。请参阅引导加载程序开发的通用提示:https://dev59.com/mVwY5IYBdhLWcg3wWmxn#32705076 - Peter Cordes

1

这是我自己尝试回答的问题。

系统虚拟化:理解IO虚拟化和超级监视器的作用

虚拟化

虚拟化作为一个概念,使得多个/不同的应用程序可以在相同的底层硬件上共存,而彼此之间并不知道对方的存在。

例如,完整的操作系统如Windows、Linux、Symbian等及其应用程序可以在同一平台上共存。所有计算资源都被虚拟化了。

这意味着上述任何一台机器都无法访问物理资源。唯一能够访问物理资源的实体是一个名为虚拟机监视器(也称为超级监视器)的程序。

现在这很重要,请仔细阅读和反复阅读。

超级监视器为上述每台机器提供了一个虚拟化环境。由于这些机器访问的不是物理硬件,而是虚拟化硬件,因此它们被称为虚拟机。

举个例子,Windows内核可能想要启动一个物理计时器(系统资源)。假设该计时器是内存映射IO。Windows内核在计时器地址上发出一系列Load/Store指令。在非虚拟化环境中,这些Load/Store将导致计时器硬件的编程。

然而,在虚拟化环境中,这些基于Load/Store的物理资源访问将导致陷阱/故障。陷阱由超级监视器处理。超级监视器知道Windows试图编程计时器。超级监视器为每个虚拟机维护计时器数据结构。在这种情况下,超级监视器更新了为Windows创建的计时器数据结构。然后它编程真正的计时器。计时器生成的任何中断都首先由超级监视器处理。更新虚拟机的数据结构并调用后者的中断服务例程。

长话短说,Windows在非虚拟化环境中所做的一切都做到了。在这种情况下,它的操作导致更新的不是真实的系统资源,而是虚拟资源(上述数据结构)。因此,所有虚拟机都认为它们正在访问底层硬件;实际上,所有对物理硬件的访问都是通过超级监视器进行调解的。

以上所述的一切都是关于完全/经典虚拟化的。大多数现代CPU不适合进行经典虚拟化。陷阱/故障并不适用于所有指令。因此,现代设备上的超级监视器很容易被绕过。

这就是Para-virtualization产生的地方。虚拟机源代码中的敏感指令被替换为对Hypervisor的调用。上面的load/store片段可以被类似以下的调用所替换:

Hypervisor_Service(Timer Start, Windows, 10ms); 

仿真

仿真是与虚拟化相关的主题。想象一种情况,原本为ARM编译的程序被制作成在ATMEL CPU上运行。ATMEL CPU运行一个仿真器程序,解释每个ARM指令并在ATMEL平台上模拟必要的操作。因此,仿真器提供了一个虚拟化环境。

在这种情况下,系统资源的虚拟化不是通过陷阱和执行模型来执行的。


你还是不正确。Hypervisor可以直接将硬件映射到操作系统。在你的情况下,Symbian/Linux在hypervisor下都可以物理访问硬件。然而,访问受到HYPERVISOR的控制。事实上,这是最有效和期望的方式。Symbian可能能够访问无线电,Linux则可以访问屏幕。这种访问是由hypervisor授予的,这就是虚拟化。 - artless noise
如果操作系统可以直接访问硬件,那么访问的是物理机器而不是虚拟机。您所描述的是资源的某种分区。我一直认为所有敏感/控制指令(在外围地址空间上进行加载/存储、CPU状态字更改等)都会陷入到超级监视器中。其他指令则会本地执行。 - Raj
不,那是低效的模式。通常外围地址映射到客户操作系统。这种映射由超级监视器控制。在许多实现中,这是通过MMU完成的。对于部分虚拟化,客户操作系统无法设置MMU。除非没有其他方法,否则超级监视器不会模拟硬件,因为这样做非常慢。 - artless noise

0

虚拟化和仿真基本上是相同的东西。这两个词所暗示的一个概念是相同的,即这两个词是同一事物的方面。这在QEMU中得到了证明,它是一个快速的仿真器,可以执行硬件虚拟化

你可以把这个事物看作是模拟。但模拟这个词也可能会让人感到困惑

首先我们可以定义这些词的共同含义。

  • 模拟:使一件事情做另一件事情。
  • 仿真:使一个系统完全复制另一个系统。
  • 虚拟化:允许在另一个系统内运行一个系统。

现在我们展示这些词的意思基本相同。例如,在模拟中,您正在使用另一个系统创建一个系统的副本。这是仿真的常见含义。在虚拟化中,您希望您的虚拟化系统像真实系统一样运行。也就是说,理想情况下它像一个副本,即使它可能被不同地实现,并且可能不会完全“模拟”硬件。这与模拟基本相同。在仿真中,您模拟另一个系统等。

因此,我们可以看到这些词有些可以互换。其基本概念是模拟。

在虚拟化中,例如操作系统虚拟化(“虚拟机”),我们正在创建一个像操作系统一样运行的系统。它可能使用底层硬件、虚拟机监视器或其他东西的技巧来提高性能和安全性。但最终它只是操作系统的模拟。通常使用“虚拟机”一词时,它并不是机器的精确副本(如模拟器)。它只做足够的工作,以允许程序在真实操作系统上按预期运行。

在仿真中,通常意味着模拟是“精确的”。在硬件仿真中,您复制了硬件系统的所有功能。这意味着您已经创建了硬件的仿真。您可以说您创建了硬件的虚拟化,但这里虚拟化略有不同。虚拟化意味着创建一个隔离的环境,而仿真并不一定意味着这一点。因此,硬件仿真器可能会为硬件提供与硬件本身相同的接口,但仿真器的实现可能依赖于全局内存,因此如果您尝试同时运行两个仿真器,它们将互相干扰。这就是虚拟化解决的问题,它隔离了仿真。
希望这能帮到您。

0

一个更近期的回应:

通过我的研究,我可以说这是一个更好的回应来理解概念如何出现:

仿真的第一个概念实际上可以追溯到第一台计算机Colossus。它在1941年被英国政府用于模拟纳粹恩格玛密码机的功能。仿真理论于1962年开发,并由三名IBM工程师从三个不同的角度构思。

仿真意味着模仿目标的行为,可以是硬件,例如emu8086仿真器,也可以是软件,例如模拟来自某个网络端口的服务。

您想模仿目标提供的一组功能,也许您对内部机制不感兴趣。

为什么要这样做?为了控制这些功能。为什么要控制?有很多原因,这是一个非常大的主题,这里无法讨论。但请记住,您想处于事物的背后。

但是这样的过程对性能来说是昂贵的。您有一条指令,需要执行很多其他指令。也许您只对其中一些指令进行控制感兴趣。因此,我们希望允许一些指令以本地方式执行。

那么当所有这些指令执行变得本地化时会发生什么?那么你就有了理想的虚拟化。你可以虚拟化任何软件,但今天的趋势是从操作系统的虚拟化转向应用程序的虚拟化。我之所以说是理想的,是因为这种软件在每个硬件上都有不同的执行方式,因此还需要模拟一些指令。重要的是要理解,今天大多数虚拟化技术不仅仅是关于虚拟化,也涉及到仿真。

另外请注意,在我们从仿真过渡到虚拟化的过程中,系统的输入被减少了,因为虚拟化只接受软件作为输入。控制这些指令流的控制器称为超级监视器


0

虚拟化可能发生在计算机体系结构的不同层次上,这些层次(从高到低)为:1:应用程序,2:库,3:操作系统,4:硬件抽象层(HAL),5:指令集架构(ISA)。 在后一层下面是硬件。 通常,某个层通过利用较低层在其接口中公开的指令来利用较低层提供的服务。
请注意,服务的使用与分层并不严格相关,因为某些层可以跳过下面的层,并利用从较低层获取的指令。例如,应用程序可以直接向HAL层提供某些指令,跳过库和操作系统层。

“模拟指令”是指截获并映射一个针对计算机体系结构(虚拟)某个层级的指令,将其转换为不同计算机体系结构(非虚拟)相同层级的一个或多个指令序列。
虚拟化层可以放置在计算机体系结构的不同层级上,这一点可能会引起混淆。例如,在硬件抽象层(如VMware、VirtualBox)进行虚拟化时,虚拟层被放置在HAL层和操作系统层之间。操作系统利用虚拟HAL层的指令,然后由超级监视程序将某些虚拟ISA(指令集架构)映射到物理系统的ISA。当所有指令都被模拟时,我们谈论的是完全模拟,这是虚拟化的一种特殊情况。在虚拟化中,通常我们尝试使一层直接执行非虚拟层的指令,以提高性能。
另一个例子是将虚拟化层放置在操作系统上(操作系统级虚拟化):在这种情况下,虚拟机被命名为容器(例如Docker)。它包括从应用程序到操作系统(包括)的各个层级。
总之,仿真与单个指令相关,而“完全仿真”发生在我们拦截和映射某个层的所有指令时。通常,“完全仿真”一词用于虚拟化层位于ISA级别(可能是最低级别)的情况。在这种情况下,虚拟机包括从应用程序到ISA的所有级别,并且拦截和映射所有ISA。这通常用于虚拟化利基产品,例如Cisco路由器(例如使用QEMU)或90年代的视频游戏控制台,其架构与通常可用的计算机完全不同。但请注意,也可能在其他级别进行“完全仿真”,这通常是不必要的。

0

我认为将虚拟化与仿真相对立是一种常见的误解,因为它们是不可比较的。当人们谈论虚拟化时,他们大多数想到的是type 2 hypervisors所做的事情。

根据wikipedia的说法,虚拟化是:

虚拟化(有时缩写为v12n)是创建某物的虚拟(而非实际)版本的行为,包括虚拟计算机硬件平台、存储设备和计算机网络资源。

这个定义适用于仿真和类型2虚拟机。因此,仿真器是虚拟化的一个子类型,而类型2虚拟机是另一个子类型。两者都可以让您运行虚拟机,但它们的工作方式和使用方式通常不同。许多虚拟机实际上依赖于这两种技术来实现其目标。

此外,模拟并不总是完全复制原始硬件1:1(这是设计上的,而不是缺乏文档),例如DOSBox模拟了一种实际不存在的PC类型,或者高级模拟器(如旧版Ultra HLE)。这使得模拟器更加高效(但有破坏软件兼容性的风险)。其他模拟器也会出于不同目的这样做:扩展原始硬件的功能(例如dolphin可以让您在4K下运行游戏,或者PS1模拟器可以显著提高3D质量,或者最近,一个带有修改PPU的SNES模拟器可以输出16:9图形,并用于修补过的超级马里奥世界以在宽屏下运行)。
一些模拟器还可以使用硬件资源,例如视频卡。 Connectix VirtualPC就是一个例子,它是基于PowerPC的Mac的旧PC模拟器。当时,Macs和PC都有PCI插槽,Connectix VirtualPC让您可以使用实际存在于Mac上(也存在于PC上)的视频卡。
我希望这能澄清事情。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接