《ARM SMMU原理与IOMMU技术(“VT-d” DMA、I/O虚拟化、内存虚拟化)》

《提升KVM异构虚拟机启动效率:透传(pass-through)、DMA映射(VFIO、PCI、IOMMU)、virtio-balloon、异步DMA映射、预处理》

《内核引导参数IOMMU与INTEL_IOMMU有何不同?》

《DMAR(DMA remapping)与 IOMMU》

《Linux驱动:VFIO概述(vfio/iommu/device passthrough)》

《Linux内核:VFIO 内核文档 (翻译)》

《Linux内核:VFIO Mediated Device(vfio-mdev)内核文档(翻译)》

目录

1. Virtual Function I/O (VFIO) Mediated devices[1]

2. Registration(注册)接口

物理设备驱动接口

3. Mediated设备管理接口sysfs

mdev_bus类目录中的链接

sysfs下每个物理设备的目录和文件

mdev设备的热插拔

4. mdev的转换(Translation)API

5. 简单代码样例

参考


原文为vfio mediated device内核文档[5],我翻译一下。

1. Virtual Function I/O (VFIO) Mediated devices[1]


对没有内置SR-IOV功能的设备进行DMA虚拟化的需求越来越多。以前,为了虚拟化一个这样的设备,开发者需要自己开发管理接口和API,然后把它们集成到用户态应用中。为了简化这种用户空间软件集成,我们找出了这种设备公共需求然后开发了一种统一的接口。

VFIO驱动框架为直接设备访问提供了统一的API。它将设备直接访问安全地(以一种IOMMU保护的环境)暴露给用户,是一种IOMMU/设备无关的框架。此框架用于多种设备,如GPU、网卡和计算加速器等。有了这种直接设备访问,虚拟机或者用户态应用可以直接访问物理设备。Mdeiated devices便是重用了VFIO这种框架。

Mediated core driver为mdiated device提供了一个公共的管理接口,它可以被不同类型的设备驱动所利用。这个模块提供了的通用接口可以进行如下操作:

  • 创建和删除mediated device(中点设备)
  • 把一个mediated deivce加入或移出某个总线驱动
  • 把一个mediated device加入或移出某个IOMMU group

Mediated core driver也提供注册总线驱动的接口。比如,一个mediated VFIO mdev驱动就是为mediated devices设计的,并且支持VFIO的API。Mediated bus driver可以将一个mediated device加入或者移出一个VFIO group。

以下的上层图展示了VFIO mediated driver框架的主要组件和接口。这张图展示了NVIDIA、Intel和IBM设备,因为这些设备是首先使用这些模块的。

     +---------------+|               || +-----------+ |  mdev_register_driver() +--------------+| |           | +<------------------------+              || |  mdev     | |                         |              || |  bus      | +------------------------>+ vfio_mdev.ko |<-> VFIO user| |  driver   | |     probe()/remove()    |              |    APIs| |           | |                         +--------------+| +-----------+ ||               ||  MDEV CORE    ||   MODULE      ||   mdev.ko     || +-----------+ |  mdev_register_device() +--------------+| |           | +<------------------------+              || |           | |                         |  nvidia.ko   |<-> physical| |           | +------------------------>+              |    device| |           | |        callbacks        +--------------+| | Physical  | || |  device   | |  mdev_register_device() +--------------+| | interface | |<------------------------+              || |           | |                         |  i915.ko     |<-> physical| |           | +------------------------>+              |    device| |           | |        callbacks        +--------------+| |           | || |           | |  mdev_register_device() +--------------+| |           | +<------------------------+              || |           | |                         | ccw_device.ko|<-> physical| |           | +------------------------>+              |    device| |           | |        callbacks        +--------------+| +-----------+ |+---------------+

2. Registration(注册)接口


Mediated core driver提供了如下类型的注册接口:

  • mediated总线驱动的注册接口
  • 物理设备驱动接口

Mediated总线驱动注册接口

为mediated总线驱动设计的注册接口提供了如下接口来表示mediated设备的驱动:

/*
* struct mdev_driver [2] - Mediated device's driver
* @name: driver name
* @probe: called when new device created
* @remove: called when device removed
* @driver: device driver structure
*/
struct mdev_driver {
const char *name;
int (*probe) (struct device *dev);
void (*remove) (struct device *dev);
struct device_driver driver;
};

一个mdev的dediated总线驱动应该在函数调用中使用这个结构来从mediated core driver中注册和注销(unregister)他自己:

  • 注册:
extern int mdev_register_driver(struct mdev_driver *drv,
struct module *owner);
  • 注销:
extern void mdev_unregister_driver(struct mdev_driver *drv);

这个mediated总线驱动是负责从VFIO group中添加(设备bound时)和删除(设备unbound时)mediated设备(mdev)。

物理设备驱动接口


物理设备驱动接口提供了mdev_parent_ops[3]结构来定义API,用于管理mediated core driver中和物理设备相关的工作。

The structures in the mdev_parent_ops structure are as follows:

mdev_parent_ops结构中的数据结构如下:

  • dev_attr_groups: parent device的属性
  • mdev_attr_groups: mediated device的属性
  • supported_config: 定义所支持配置的属性

The functions in the mdev_parent_ops structure are as follows:

mdev_parent_ops结构中的函数如下:

  • create: 在driver中为一个mdev分配基本的资源
  • remove: 当一个mdev被销毁时在driver中free掉相关资源

(Note that mdev-core provides no implicit serialization of create/remove
callbacks per mdev parent device, per mdev type, or any other categorization.
Vendor drivers are expected to be fully asynchronous in this respect or
provide their own internal resource protection.)

(注意,mdev-core不为每个mdev parent device、每个mdev类型或者任何其他配置提供create/remove回调的隐式序列化。提供商驱动被期望完全得同步或者提供他们自己的内部资源保护。)

mdev_parent_ops结构中的回调如下:

  • open: 打开mdev的回调
  • close: 关闭mdev的回调
  • ioctl: mdev的ioctl回调 callback of mediated device
  • read : read模拟回调
  • write: write模拟回调
  • mmap: mmap模拟回调

一个驱动应该用在注册到mdev core driver时用mdev_parent_ops这个结构

extern int mdev_register_device(struct device *dev,
const struct mdev_parent_ops *ops);

However, the mdev_parent_ops structure is not required in the function call
that a driver should use to unregister itself with the mdev core driver::

但是,mdev_parent_ops结构在从mdev core driver注销时并不需要:

extern void mdev_unregister_device(struct device *dev);

3. Mediated设备管理接口sysfs


The management interface through sysfs enables user space software, such as
libvirt, to query and configure mediated devices in a hardware-agnostic fashion.
This management interface provides flexibility to the underlying physical
device’s driver to support features such as:

管理接口是通过sysfs来让用户态软件(如libvirt)进行请求和配置mdevs的,这种管理是一种硬件无关的形式。这种管理接口给底层硬件设备驱动提供了灵活的特性支持,比如:

  • mdev的热插拔
  • 多个mdev在一个虚拟机中
  • 来自不同物理设备的多个mdev

mdev_bus类目录中的链接


/sys/class/mdev_bus/这个目录包含到已注册到mdev core driver设备的链接。

sysfs下每个物理设备的目录和文件


|- [parent physical device]
|--- Vendor-specific-attributes [optional]
|--- [mdev_supported_types]
| |--- [<type-id>]
| | |--- create
| | |--- name
| | |--- available_instances
| | |--- device_api
| | |--- description
| | |--- [devices]
| |--- [<type-id>]
| | |--- create
| | |--- name
| | |--- available_instances
| | |--- device_api
| | |--- description
| | |--- [devices]
| |--- [<type-id>]
| |--- create
| |--- name
| |--- available_instances
| |--- device_api
| |--- description
| |--- [devices]

其中:

  • [mdev_supported_types]:列出了单签支持的mdev的种类(mediated device type)和详细信息,type-id, device_api, 和available_instances应给被厂商驱动提供的信息:
  • type-id: type-id这个名字是用设备驱动字符串作为厂商驱动字符串前缀的名。这个名字的格式如下:
sprintf(buf, "%s-%s", dev_driver_string(parent->dev), group->name);

(或者用mdev_parent_dev(mdev)来访问core mdev代码外的parent device)

  • device_api:这个属性用来指明什么设备API被创建了,比如,”vfio-pci”是给PCI设备用的。
  • available_instances:这个属性展示了可以被创建的type-id类设备数。
  • [device]:这个目录包含了到被创建的type-id设备的链接。
  • name:展示了人类能看懂的名字,此项可选。
  • description:展示简单说明的类型特性、描述,此项可选

### sysfs下每个mdev设备的目录和文件```bash
|- [parent phy device]
|--- [$MDEV_UUID]
|--- remove
|--- mdev_type {link to its type}
|--- vendor-specific-attributes [optional]

其中:

  • remove (只写):往其中写”1″会销毁mdev设备。如果设备处于活跃状态并且厂商的驱动不支持热插拔,那么厂商的驱动可以让remove回调失败。

例子:

echo 1 > /sys/bus/mdev/devices/$mdev_UUID/remove

mdev设备的热插拔


mdev设备可以在运行时进行创建和绑定。热插拔mdev的步骤和热插拔PCI设备的步骤相同。

4. mdev的转换(Translation)API


以下API用于提供在VFIO驱动中从User PFN到Host PFN的转换:

extern int vfio_pin_pages(struct device *dev, unsigned long *user_pfn,
int npage, int prot, unsigned long *phys_pfn);extern int vfio_unpin_pages(struct device *dev, unsigned long *user_pfn,
int npage);

这些函数会回调后端IOMMU模块(struct vfio_iommu_driver_ops[4]结构中的pin_pages函数和unpin_pages函数)。挡墙这些回调在TYPE1 IOMMU模块中被支持。其他IOMMU后端模块中(如PPC64 sPAPR模块)若想支持,他们就需要提过这两个回调函数的实现。

5. 简单代码样例


samples/vfio-mdev/文件夹中的mtty.c是一个展示mdev框架怎么用的简单驱动程序。

这个简单驱动创建了一个mdev设备来模拟一个PCI串口设备。

Step 1 创建和加载mtty.ko模块:

这步会创建一个dummy设备/sys/devices/virtual/mtty/mtty/

sysfs中的设备目录如下:

# tree /sys/devices/virtual/mtty/mtty/
/sys/devices/virtual/mtty/mtty/
|-- mdev_supported_types
| |-- mtty-1
| | |-- available_instances
| | |-- create
| | |-- device_api
| | |-- devices
| | `-- name
| `-- mtty-2
| |-- available_instances
| |-- create
| |-- device_api
| |-- devices
| `-- name
|-- mtty_dev
| `-- sample_mtty_dev
|-- power
| |-- autosuspend_delay_ms
| |-- control
| |-- runtime_active_time
| |-- runtime_status
| `-- runtime_suspended_time
|-- subsystem -&gt; ../../../../class/mtty
`-- uevent

Step 2 用这个dummy设备创建一个mdev设备:

# echo "83b8f4f2-509f-382f-3c1e-e6bfe0fa1001" &gt; \
/sys/devices/virtual/mtty/mtty/mdev_supported_types/mtty-2/create

Step 3 为qemu-kvm添加如下参数:

-device vfio-pci,\
sysfsdev=/sys/bus/mdev/devices/83b8f4f2-509f-382f-3c1e-e6bfe0fa1001

Step 4 启动虚拟机

In the Linux guest VM, with no hardware on the host, the device appears
as follows::

在Linux为GuestOS的虚拟机中,设备会被这样显示:

# lspci -s 00:05.0 -xxvv
00:05.0 Serial controller: Device 4348:3253 (rev 10) (prog-if 02 [16550])
Subsystem: Device 4348:3253
Physical Slot: 5
Control: I/O+ Mem- BusMaster- SpecCycle- MemWINV- VGASnoop- ParErr-
Stepping- SERR- FastB2B- DisINTx-
Status: Cap- 66MHz- UDF- FastB2B- ParErr- DEVSEL=medium &gt;TAbort-
&lt;TAbort- &lt;MAbort- &gt;SERR- &lt;PERR- INTx-
Interrupt: pin A routed to IRQ 10
Region 0: I/O ports at c150 [size=8]
Region 1: I/O ports at c158 [size=8]
Kernel driver in use: serial
00: 48 43 53 32 01 00 00 02 10 02 00 07 00 00 00 00
10: 51 c1 00 00 59 c1 00 00 00 00 00 00 00 00 00 00
20: 00 00 00 00 00 00 00 00 00 00 00 00 48 43 53 32
30: 00 00 00 00 00 00 00 00 00 00 00 00 0a 01 00 00

在Linux为GuestOS的虚拟机中,dmesg会有如下输出:

serial 0000:00:05.0: PCI INT A -&gt; Link[LNKA] -&gt; GSI 10 (level, high) -&gt; IRQ 10
0000:00:05.0: ttyS1 at I/O 0xc150 (irq = 10) is a 16550A
0000:00:05.0: ttyS2 at I/O 0xc158 (irq = 10) is a 16550A

Step 5 在Linux为guestOS的虚拟机中,查看串口设备:

# setserial -g /dev/ttyS*
/dev/ttyS0, UART: 16550A, Port: 0x03f8, IRQ: 4
/dev/ttyS1, UART: 16550A, Port: 0xc150, IRQ: 10
/dev/ttyS2, UART: 16550A, Port: 0xc158, IRQ: 10

Step 6 用minicom或者其他终端模拟程序,打开串口/dev/ttyS1或者/dev/ttyS2并禁用硬件流控制:

Step 7 向minicom终端打字或者发数据给终端模拟程序并读数据

数据会在host mtty驱动回显。

Step 8 销毁所创建的mdev:

# echo 1 > /sys/bus/mdev/devices/83b8f4f2-509f-382f-3c1e-e6bfe0fa1001/remove

参考


  • [1] 内核中的VFIO文档Documentation/vfio.txt有VFIO的更多信息,我也在以前的博客中翻译过。
  • [2] include/linux/mdev.h文件中的struct mdev_driver结构
  • [3] include/linux/mdev.h文件中的struct mdev_parent_ops结构
  • [4] include/linux/vfio.h文件中的struct vfio_iommu_driver_ops结构
  • [5] https://github.com/torvalds/linux/blob/master/Documentation/vfio-mediated-device.txt

Linux内核:VFIO Mediated Device(vfio-mdev)内核文档(翻译)相关推荐

  1. rhel6上使用udev配置oracle asm,Red Hat Enterprise Linux 6使用udev配置Oracle ASM总结文档

    1.概述 在Red Hat Enterprise Linux (RHEL)6以前,Oracle均是使用ASMLib这个内核支持库配置ASM. ASMLIB是一种基于Linux module,专门为Or ...

  2. linux文件管理系统开发毕业,定稿毕业论文基于Linux的远程管理系统服务器端的实现word文档(范文1)...

    <[毕业论文]基于Linux的远程管理系统服务器端的实现.doc>由会员分享,可免费在线阅读全文,更多与<(定稿)毕业论文基于Linux的远程管理系统服务器端的实现(word文档)& ...

  3. linux系统引导设置,Linux操作系统GRUB引导程序配置方法大全 - 技术文档 - 新手入门 Linux时代......

    1. GRUB 介绍 计算机在启动的时候,首先由BIOS中的程序执行自检,自检通过后,就根据CMOS 的配置找到第一个可启动磁盘的MBR中的Boot Loader程序(一般在启动盘的第一个物理扇区,占 ...

  4. Linux编译open62541,open ua统一标准指导文档(ice 62541)

    [实例简介] open ua统一标准指导文档,基于C语言的.包含了节点,函数,类型等基础说明.以及open ua服务器/客户端建立的一些基本实例. Contents 1 Introduction I1 ...

  5. php linux下保存文件路径怎么写,linux下php导入带图片的word文档转为html,图片保存下来生成路径。...

    linux下yum install libreoffice yum install libreoffice-headless 如果出现异常,在页面上不一定表现出来,而是页面卡着一直没响应,通过apac ...

  6. windows/linux服务器上java使用openoffice将word文档转换为PDF(亲测可用)

    一. 前言 1. 开发过程中经常会使用java将office系列文档转换为PDF, 一般都使用微软提供的openoffice+jodconverter 实现转换文档. 2. openoffice既有w ...

  7. linux查看帮助文档的命令,Linux如何使用查看一个命令的帮助文档呢?

    摘要: 下文讲述Linux操作系统中查看命令的帮助文档的方法分享,如下所示: 实现思路: 使用 --help命令即可查看命令自带的帮助文档信息 例: 查看ls命令的帮助信息 [root@localho ...

  8. linux md文件 编辑,用Vim写md文档的简单姿势

    对于重度Vim使用者来说,编辑md文档用Vim是顺理成章的事,在此记录下来. 近期开始带学生接触Openstack开发.在8G内存的笔记本上跑个Devstack开发环境,至少要分掉4G,否则虚拟机卡成 ...

  9. linux excel pdf文件大小,为什么PDF这种格式文档运用得这么广泛

    原标题:为什么PDF这种格式文档运用得这么广泛 PDF文件格式是现在最常用的文件格式之一,在各行各业都得到了广泛的运用.与其他常见文件格式如Word或PPT文档相比(再加上我们可以使用专业的PDF阅读 ...

最新文章

  1. oracle 数据泵导出简单使用版
  2. 分享一个异步发送邮件的类
  3. css3制作左右拉伸动画菜单
  4. LeetCode_104.二叉树的最大深度
  5. Codeforces1080F. Katya and Segments Sets
  6. 分页请求json数据_Python爬虫入门教程 28-100 虎嗅网文章数据抓取 pyspider
  7. 谷歌CEO支持欧盟禁止人脸识别!微软总裁:能用“手术刀”就别用“切肉刀”...
  8. ubuntu安装vncserver实现图形化访问
  9. 手机邮箱怎么注册申请?教你用手机号如何注册电子邮箱地址
  10. 算法提高 盾神与条状项链(静态链表)
  11. DFMEA \FTA
  12. python——esc按键按下与识别
  13. nasm做一个简单的操作系统写字本(1)
  14. 阿里云GPU云服务器gn5i/gn5/gn6i/gn6v详解
  15. 有能力的人从不抱怨大环境!
  16. 善用“天时、地利、人和”,项目经理才能更有底气地要人要资源
  17. java文档注释用什么开头,极其重要
  18. 市场调研策划书_市场调查计划书范文
  19. PADS的layout单个元器件删除时提示“复用元素无法修改,首先打散复用模块”
  20. 斯坦福学者:生物智能可能是解决AI发展瓶颈的关键

热门文章

  1. redis学习-redis事务
  2. MapUtils常用方法
  3. 百度分享新浪微博无法分享图片的解决方法
  4. [No00009E]几种常见的命名规则
  5. Objective-C中的@Property详解
  6. Kryo 为什么比 Hessian 快
  7. Effective C++(9) 构造函数调用virtual函数会发生什么
  8. XPath最通俗的教程(ZZ)
  9. 4- Mybatis 的参数深入
  10. Java代码有效和片段有效_Java 9 尝鲜之交互式编程环境