CTF-虚拟机——【前置知识四】

文章目录

  • IO虚拟化
  • 基本模型
    • 平台设备模拟(Platform device emulation)
    • 用户空间设备模拟(User space device emulation)
    • 设备直通(Device passthrough)
  • 软件半虚拟化-virtio
    • 驱动程序
    • VirtQueue:传输层抽象
      • 要用到的数据结构
      • 大概流程
  • IOMMU
    • DMA重映射

IO虚拟化

由于外设设备有限,但仍然想为VM提供外设设备的功能。(另外由于处理器与外设之间的交互主要是和IO交互。所以称外设的虚拟化为IO虚拟化。)所以需要VMM通过IO虚拟化来实现为VM提供IO设备的功能。

IO虚拟化的任务:

  • 访问截获:当VM有对外设的访问操作时,VMM需要能够截获
  • 提供设备接口:VMM要为VM提供虚拟设备的接口或者物理设备的接口
  • 实现设备功能:VMM需要实现虚拟设备的功能

基本模型

平台设备模拟(Platform device emulation)

即VMM负责模拟设备的功能
VMM对设备进行仿真模拟供Gust OS共享使用

用户空间设备模拟(User space device emulation)

即主机的用户空间模拟设备的功能,模拟的虚拟设备可以通过VMM提供的接口被其他的VM调用。且设备的模拟是独立于VMM的。

设备直通(Device passthrough)

即直接将物理设备隔离给指定的VM,然后VM直接使用物理设备的功能。这提供了接近原生设备的性能(但只能被模仿,从未被超越)

软件半虚拟化-virtio

通过virtio驱动从而建立与虚拟化设备的联系,从而能够访问

  1. 完全虚拟化

不需要对GuestOS操作系统软件的源代码做任何的修改,就可以运行在这样的VMM中

在全虚拟化的虚拟平台中,GuestOS并不知道自己是一台虚拟机,它会认为自己就是运行在计算机物理硬件设备上的HostOS。因为全虚拟化的VMM会将一个OS所能够操作的CPU、内存、外设等物理设备逻辑抽象成为虚拟CPU、虚拟内存、虚拟外设等虚拟设备后,再交由GuestOS来操作使用。这样的GuestOS会将底层硬件平台视为自己所有的,但是实际上,这些都是VMM为GuestOS制造了这种假象。

  1. 半虚拟化

需要对GuestOS的内核代码做一定的修改,才能够将GuestOS运行在半虚拟化的VMM中。

半虚拟化通过在GuestOS的源代码级别上修改特权指令来回避上述的虚拟化漏洞。

修改内核后的GuestOS也知道自己就是一台虚拟机。所以能够很好的对核心态指令和敏感指令进行识别和处理,但缺点在于GuestOS的镜像文件并不通用。

半虚拟化技术增加专用的API 接口以优化客户端的指令,共享系统硬件驱动,更大限度的提高了计算机的性能,实现用软件接口来代替计算机硬件的功能,解决了全虚拟化技术中二进制转换造成的性能浪费问题。

驱动程序

驱动本质上是软件代码,其主要作用是计算机系统与硬件设备之间完成数据传送的功能,只有借助驱动程序,两者才能通信并完成特定的功能。如果一个硬件设备没有驱动程序,只有操作系统是不能发挥特有功效的,也就是说驱动程序是介于操作系统与硬件之间的媒介,实现双向的传达,即将硬件设备本身具有的功能传达给操作系统,同时也将操作系统的标准指令传达给硬件设备,从而实现两者的无缝连接。

VirtQueue:传输层抽象

virtqueue 为 virtio 中用以进行数据传输的关键结构,其本身表示一个数据队列:由一方向队列中添加 buffer,另一方从队列中取出 buffer——通过这样的方式实现了 Guest 与 Host 之间基本的数据传输模型。

为了减少模型的复杂性,我们使用两个 virtqueue 来实现 Guest 与 Host 之间的双向通信:一个virtqueue用来从Guest到Host,一个用来Host到Guest

要用到的数据结构

这是一个描述符(Descriptor)的结构

struct vring_desc
{
    __u64 addr;     // 描述符对应的起始地址
    __u32 len;      // 从起始地址开始占的大小空间
    __u16 flags;    // 该描述符的属性
    __u16 next;     // 对应的下一个描述符的下标
};

这是一个Avali结构

struct vring_avail
{
    __u16 flags; //该结构内所有描述符的附加属性
    __u16 idx;  // 下一次要加描述符对应在ring数组中的下标
    __u16 ring[NUM]; //存储描述符的
};

这是一个Used结构

struct vring_used_elem 
{
    __u32 id;  //描述符的值
    __u32 len; //允许从描述符对应的地址空间中写入的长度
};

struct vring_used
{
    __u16 flags; //该结构内所有描述符的附加属性
    __u16 idx; //下一次要加描述符对应在ring数组中的下标
    struct vring_used_elem ring[];//存储描述符的
};

大概流程

CTF-虚拟机——【前置知识四】_第1张图片
某位大佬的解析

IOMMU

IOMMU 即 Input/Output Memory Management Unit,其功能类似于 CPU 中的 MMU,是一个向设备侧提供地址翻译功能的单元。
IOMMU与MMU二者区别
CTF-虚拟机——【前置知识四】_第2张图片
IOMMU功能
LAPIC (Local Advanced Programmable Interrupt Controller)

  • DMA 重映射( DMA remapping):有着 DMA 功能的设备可以使用虚拟地址,通过 IOMMU 转换为物理地址进行直接内存访问。
  • 中断重映射(Interrupt remapping):IOMMU 会拦截设备产生的中断,根据中断重映射表产生新的中断请求发送给 LAPIC。

DMA重映射

DMA 重映射即面向设备侧的地址访问重翻译,如下图所示,左侧是 CPU 对内存的虚拟化:MMU 利用进程页表将进程要访问的虚拟地址翻译为物理地址,又因为不同进程其页表不同,从而实现在两个进程中访问同一个虚拟地址实际上访问到不同的物理地址——DMA 重映射也是类似的原理,如下图右侧所示,当外设想要进行 DMA 时,IOMMU 会根据 “设备页表” 进行地址翻译,不同设备其页表不同,从而使得两个设备各自感知访问的是同一个地址,但实际上访问到了不同的物理地址。
CTF-虚拟机——【前置知识四】_第3张图片

半虚拟化设备的并不知道GPA与HPA的转换,所以可能访问错误,所以IOMMU需要根据Host提供的 GPA 到 HPA 之间的地址转换表再进行DMA映射,这样外设就能正常地访问到 Guest 的物理内存

你可能感兴趣的:(从零自制虚拟机,服务器,linux,网络)