[SPDK/NVMe存储技术分析]007 - 初识UIO
注: 要进一步搞清楚SSD盘对应的PCI的BAR寄存器的映射,有必要先了解一下UIO(Userspace I/O)。
UIO(Userspace I/O)是运行在用户空间的I/O技术。在Linux系统中,一般的设备驱动都是运行在内核空间,而在用户空间使用应用程序调用即可。而UIO则是将设备驱动的很少一部分运行在内核空间,而在用户空间实现驱动的绝大多数功能。那么,在内核空间UIO要做的事情就变得很简单,分为两种:
- 分配和记录设备需要的资源和注册UIO设备
- 实现必须在内核空间实现的中断处理函数
为了对UIO有一个直观的认识,先上个图:
了解了UIO 驱动在Linux系统中的位置后,让我们对参考资料(Linux User Space Device Drivers)的部分内容做一个中英文对照翻译以加深对UIO的理解。
1 Device Driver Architectures | 设备驱动架构
- Linux device drivers are typically designed as kernel drivers running in kernel space
典型的Linux设备驱动都是被设计为运行在内核空间的内核驱动 - User space I/O is another alternative device driver architecture that has been supported by the Linux kernel since 2.6.24
从Linux内核版本2.6.24开始,就支持另一种可作为内核设备驱动的替代方案的设备驱动架构,也就是用户空间I/O - People in the Linux kernel community may not always agree on the need to have user space I/O
在Linux内核社区的人们不总是赞成使用用户空间I/O - Industrial I/O cards have been taking advantage of user space I/O for quite some time
在工业中使用的I/O卡利用用户空间I/O的优点已经有一阵子了 - For some types of devices, creating a Linux kernel driver may be overkill
对某些类型的设备来说,创建对应的Linux内核驱动很可能代价太高 - Soft IP for FPGAs can have unique requirements that don't always fit the mold
FPGA的软IP有独特的需求,将驱动放在内核实现并不总是适合的
2 Legacy User Space Driver Methods (/dev/mem) | 传统的用户态驱动实现方法(/dev/mem)
- A character driver referred to as /dev/mem exists in the kernel that will map device memory into user space
- With this driver user space applications can access device memory
- Memory access can be disabled in the kernel configuration as this is a big security hole (CONFIG_STRICT_DEVMEM)
- Must be root user
- A great tool for prototyping or maybe testing new hardware, but is not considered to be an acceptable production solution for a user space device driver
- Since it can map any address into user space a buggy user space driver could crash the kernel
3 Introduction to UIO | UIO概述
- The Linux kernel provides a framework for doing user space drivers called UIO
- The framework is a character mode kernel driver (in drivers/uio) which runs as a layer under a user space driver
- UIO helps to offload some of the work to develop a driver
- The "U" in UIO is not for universal
- - Devices well handled by kernel frameworks should ideally stay in the kernel (if you ask many kernel developers)
- - Networking is one area where semiconductor vendors are doing user space I/O to get improved performance
- UIO handles simple device drivers really well
- - Simple driver: Device access and interrupt processing with no need to access kernel frameworks
4 Kernel Space Driver Characteristics | 内核空间驱动的特点
4.1 Advantages | 优点
- Runs in kernel space in the highest privilege mode to allow access to interrupts and hardware resources
- There are a lot of kernel services such that kernel space drivers can be designed for complex devices
- The kernel provides an API to user space which allows multiple applications to access a kernel space driver simultaneously
- - Larger and more scalable software systems can be architected
- Many drivers tend to be kernel space
- - Asking questions in the open source community is going to be easier
- - Pushing drivers to the open source community is likely easier
4.2 Disadvantages | 缺点
- System call overhead to access drivers
- - A switch from user space to kernel space (and back) is required
- - Overhead can be non-deterministic having impact on real time applications
- Challenging learning curve for developers
- - The kernel API is different from the application level API such that it takes time to become productive
- Bugs can be fatal causing a kernel crash
- Challenging to debug
- - Kernel code is highly optimized and there are different debug tools
- Frequent kernel API changes
- - Kernel drivers built for one kernel version may not build for another
5 User Space Device Driver Characteristics | 用户空间驱动的特点
5.1 Advantages | 优点
- Less challenging to debug as debug tools are more readily available and common to normal application development
- User space services such as floating point are available
- Device access is very efficient as there is no system call required
- The application API of Linux is very stable
- The driver can be written in any language, not just "C"
5.2 Disadvantages | 缺点
- No access to the kernel frameworks and services
- - Contiguous memory allocation, direct cache control, and DMA are not available
- - May have to duplicate kernel code or use a kernel driver to supplement
- Interrupt handling cannot be done in user space
- - It must be handled by a kernel driver which notifies user space causing some delay
- There is no predefined API to allow applications to access the device driver
- - Concurrency must also be considered if multiple applications access a driver
6 UIO Framework Features | UIO框架的特性
- There are two distinct UIO device drivers provided by Linux in drivers/uio
- UIO Driver (drivers/uio.c)
- - For more advanced users as a minimal kernel space driver is required to setup the UIO framework
- - This is the most universal and likely to handle all situations since the kernel space driver can be very custom
- - The majority of work can be accomplished in the user space driver
- UIO Platform Device Driver (drivers/uio_pdev_irqgen.c)
- This driver augments the UIO driver such that no kernel space driver is required
- It provides the required kernel space driver for uio
- It works with device tree making it easy to use
- The device tree node for the device needs to use "generic uio" in it's compatible
- Best starting point since no kernel space code is needed
- This driver augments the UIO driver such that no kernel space driver is required
7 UIO Driver Kernel Configuration | 支持UIO驱动所需要的内核配置
- UIO drivers must be configured in the Linux kernel
CONFIG_UIO=y
CONFIG_UIO_PDRV_GENIRQ=y
8 UIO Platform Device Driver Details | UIO平台服务驱动详解
- The user provides only a user space driver
- The UIO platform device driver configures from the device tree and registers a UIO device
- The user space driver has direct access to the hardware
- The user space driver gets notified of an interrupt by reading the UIO device file descriptor
9 Kernel UIO API - Sys Filesystem
- The UIO driver in the kernel creates file attributes in the sys filesystem describing the UIO device
- /sys/class/uio is the root directory for all the file attributes
- A separate numbered directory structure is created under /sys/class/uio for each UIO device
- - First UIO device: /sys/class/uio/uio0
- - /sys/class/uio/uio0/name contains the name of the device which correlates to the name in the uio_info structure
- - /sys/class/uio/uio0/maps is a directory that has all the memory ranges for the device
- - Each numbered map directory has attributes to describe the device memory including the address, name, offset and size
- /sys/class/uio/uio0/maps/map0
10 User Space Driver Flow | 用户态驱动工作流程
- 01 - The kernel space UIO device driver(s) must be loaded before the user space driver is started (if using modules)
- 02 - The user space application is started and the UIO device file is opened (/dev/uioX where X is 0, 1, 2 ...)
- - From user space, the UIO device is a device node in the file system just like any other device
- 03 - The device memory address information is found from the relevant sysfs directory, only the size is needed
- 04 - The device memory is mapped into the process address space by calling the mmap() function of the UIO driver
- 05 - The application accesses the device hardware to control the device
- 06 - The device memory is unmapped by calling munmap()
- 07 - The UIO device file is closed
11 User Space Driver Example | 用户态驱动示例
1 #define UIO_SIZE "/sys/class/uio/uio0/maps/map0/size"
2
3 int main(int argc, char **argv)
4 {
5 int uio_fd;
6 unsigned int uio_size;
7 FILE *size_fp;
8 void *base_address;
9
10 /*
11 * 1. Open the UIO device so that it is ready to use
12 */
13 uio_fd = open("/dev/uio0", O_RDWR);
14
15 /*
16 * 2. Get the size of the memory region from the size sysfs file
17 * attribute
18 */
19 size_fp = fopen(UIO_SIZE, O_RDONLY);
20 fscanf(size_fp, "0x%08X", &uio_size);
21
22 /*
23 * 3. Map the device registers into the process address space so they
24 * are directly accessible
25 */
26 base_address = mmap(NULL, uio_size,
27 PROT_READ|PROT_WRITE,
28 MAP_SHARED, uio_fd, 0);
29
30 // Access to the hardware can now occur ...
31
32 /*
33 * 4. Unmap the device registers to finish
34 */
35 munmap(base_address, uio_size);
36
37 ...
38 }
12 Mapping Device Memory Details | 设备内存映射详解
- The character device driver framework of Linux provides the ability to map device memory into a user space process address space
- A character driver may implement the mmap() function which a user space application can call
- The mmap() function creates a new mapping in the virtual address space of the calling process
- - A virtual address, corresponding to the physical address specified is returned
- - It can also be used to map a file into a memory space such that the contents of the file are accessed by memory reads and writes
- Whenever the user space program reads or writes in the virtual address range it is accessing the device
- This provides improved performance as no system calls are required
13 Mapping Device Memory Flow | 设备内存映射流程
14 User Space Application Interrupt Processing | 用户空间应用程序中断处理
- Interrupts are never handled directly in user space
- The interrupt can be handled by the UIO kernel driver which then relays it on to user space via the UIO device file descriptor
- The user space driver that wants to be notified when interrupts occur calls select() or read() on the UIO device file descriptor
- - The read can be done as blocking or non-blocking mode
- read() returns the number of events (interrupts)
- A thread could be used to handle interrupts
- Alternatively a user provided kernel driver can handle the interrupt and then communicate data to the user space driver through other mechanisms like shared memory
- - This may be necessary for devices which have very fast interrupts
15 User Space Application Interrupt Processing Example | 用户空间应用程序中断处理示例
1 int pending = 0;
2 int reenable = 1;
3
4 /*
5 * 1. The UIO device is opened as previously described
6 */
7 int uio_fd = open("/dev/uio0", O_RDWR);
8
9 /*
10 * 2. Read the UIO device file descriptor to wait for an interrupt,
11 * the read blocks by default, a non blocking read can also be used
12 *
13 * NOTE: The pending variable contains the number of interrupts that have
14 * occurred if multiple
15 */
16 read(uio_fd, (void *)&pending, sizeof(int));
17
18
19 //
20 // add device specific processing like acking the interrupt in the device here
21 //
22
23
24 /*
25 * 3. Re-enable the interrupt at the interrupt controller level
26 */
27 write(uio_fd, (void *)&reenable, sizeof(int));
Part II: Advanced UIO With Both User Space Application and Kernel Space Driver
16 UIO Driver Details | UIO驱动详解
- The user provides a kernel driver and a user space driver
- The kernel space driver is a platform driver configuring from the device tree and registering a UIO device
- The kernel space driver can also provide an interrupt handler in kernel space
- The user space driver has direct access to the hardware
17 Kernel UIO API - Basics | 内核UIO API基础
- The API is small and simple to use API小且易用
struct uio_info
-- name : device name
-- version : device driver version
-- irq : interrupt number
-- irq_flags : flags for request_irq()
-- handler : driver irq handler (optional)
-- mem[] : memory regions that can be mapped to user space
o addr : memory address
o memtype : type of memory region (physical, logical, virtual)
18 Kernel UIO API - Registration | 内核UIO API - 注册
- The function uio_register_device() connects the driver to the UIO framework
- Requires a struct uio_info as an input
- Typically called from the probe() function of a platform device driver
- Creates device file /dev/uio# (#starting from 0) and all associated sysfs file attributes
- The function uio_unregister_device() disconnects the driver from the UIO framework
- Typically called from the cleanup function of a platform device driver
- Deletes the device file /dev/uio#
19 Kernel Space Driver Example | 内核空间驱动示例
1 probe()
2 {
3 /*
4 * 1. Platform device driver initialization in the driver probe() function
5 */
6 dev = devm_kzalloc(&pdev->dev, (sizeof(struct uio_timer_dev)), GFP_KERNEL);
7 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
8 dev->regs = devm_ioremap_resource(&pdev->dev, res);
9 irq = platform_get_irq(pdev, 0);
10
11 /*
12 * 2. Add basic UIO structure initialization
13 */
14 dev->uio_info.name = "uio_timer";
15 dev->uio_info.version = 1;
16 dev->uio_info.priv = dev;
17
18 /*
19 * 3. Add the memory region initialization for the UIO
20 */
21 dev->uio_info.mem[0].name = "registers";
22 dev->uio_info.mem[0].addr = res->start;
23 dev->uio_info.mem[0].size = resource_size(res);
24 dev->uio_info.mem[0].memtype = UIO_MEM_PHYS;
25
26 /*
27 * 4. Add the interrupt initialization for the UIO
28 */
29 dev->uio_info.irq = irq;
30 dev->uio_info.handler = uio_irq_handler;
31
32 /*
33 * 5. Register the UIO device with the kernel framework
34 */
35 uio_register_device(&pdev->dev, &dev->info);
36 }
20 UIO Framework Details | UIO框架详解
- UIO Driver
- - The device tree node for the device can use whatever you want in the compatible property as it only has to match what is used in the kernel space driver as with any platform device driver
- UIO Platform Device Driver
- - The device tree node for the device needs to use "generic - uio" in it's compatible property
参考资料
- Linux User Space Device Drivers
- UIO: user-space drivers
- Howto: Accessing PCI devices from userspace
- Kernel space: the UIO interface for device drivers
- Paper: Userspace I/O drivers in a realtime context
Send a wise man on an errand, and say nothing to him. | 智者当差,无须交待。
[SPDK/NVMe存储技术分析]007 - 初识UIO的更多相关文章
- [SPDK/NVMe存储技术分析]003 - NVMeDirect论文
说明: 之所以要翻译这篇论文,是因为参考此论文可以很好地理解SPDK/NVMe的设计思想. NVMeDirect: A User-space I/O Framework for Application ...
- [SPDK/NVMe存储技术分析]002 - SPDK官方介绍
Introduction to the Storage Performance Development Kit (SPDK) | SPDK概述 By Jonathan S. (Intel), Upda ...
- [SPDK/NVMe存储技术分析]004 - SSD设备的发现
源代码及NVMe协议版本 SPDK : spdk-17.07.1 DPDK : dpdk-17.08 NVMe Spec: 1.2.1 基本分析方法 01 - 到官网http://www.spdk.i ...
- [SPDK/NVMe存储技术分析]001 - SPDK/NVMe概述
1. NVMe概述 NVMe是一个针对基于PCIe的固态硬盘的高性能的.可扩展的主机控制器接口. NVMe的显著特征是提供多个队列来处理I/O命令.单个NVMe设备支持多达64K个I/O 队列,每个I ...
- [SPDK/NVMe存储技术分析]008 - RDMA概述
毫无疑问地,用来取代iSCSI/iSER(iSCSI Extensions for RDMA)技术的NVMe over Fabrics着实让RDMA又火了一把.在介绍NVMe over Fabrics ...
- [SPDK/NVMe存储技术分析]005 - DPDK概述
注: 之所以要中英文对照翻译下面的文章,是因为SPDK严重依赖于DPDK的实现. Introduction to DPDK: Architecture and PrinciplesDPDK概论:体系结 ...
- [SPDK/NVMe存储技术分析]012 - 用户态ibv_post_send()源码分析
OFA定义了一组标准的Verbs,并提供了一个标准库libibvers.在用户态实现NVMe over RDMA的Host(i.e. Initiator)和Target, 少不了要跟OFA定义的Ver ...
- [SPDK/NVMe存储技术分析]006 - 内存屏障(MB)
在多核(SMP)多线程的情况下,如果不知道CPU乱序执行的话,将会是一场噩梦,因为无论怎么进行代码Review也不可能发现跟内存屏障(MB)相关的Bug.内存屏障分为两类: 跟编译有关的内存屏障: 告 ...
- [SPDK/NVMe存储技术分析]015 - 理解内存注册(Memory Registration)
使用RDMA, 必然关系到内存区域(Memory Region)的注册问题.在本文中,我们将以mlx5 HCA卡为例回答如下几个问题: 为什么需要注册内存区域? 注册内存区域有嘛好处? 注册内存区域的 ...
随机推荐
- 解决/WEB-INF目录下的jsp页面引入webRoot下的Js、css和图片的问题
通常把jsp页面放在webRoot的/WEB-INF下可以防止访问者直接输入页面. 而webRoot的/WEB-INF下的页面是受保护的,用户无法通过形如http://localhost:8080/t ...
- 帆软报表(finereport)雷达图钻取详细点新页面展示
添加参数栏,季度下拉框的空间名为combobox0 添加雷达图,通过第三页面做跳转 雷达图钻取.cpt为联动钻取的第三页面 添加纬度(所点击钻取的点) 参数 wd 添加季度参数 jd 值为季 ...
- 06 jQuery
BOM和DOM 1. 什么是BOM和DOM 到目前为止,我们已经学过了JavaScript的一些简单的语法.但是这些简单的语法,并没有和浏览器有任何交互. 也就是我们还不能制作一些我们经常看到的网页的 ...
- 非极大值抑制算法(Python实现)
date: 2017-07-21 16:48:02 非极大值抑制算法(Non-maximum suppression, NMS) 算法原理 非极大值抑制算法的本质是搜索局部极大值,抑制非极大值元素. ...
- 再也不用担心重装VSCode了
1. 关于Settings Sync插件 Setings Sync插件可以同步你的VSCode配置到Github Gist,当你更换电脑重新搭建VSCode环境的时候,直接使用该插件拉取你之前同步的配 ...
- php 利用 fsockopen GET/POST 提交表单及上传文件
1.GET get.php <?php$host = 'demo.fdipzone.com';$port = 80;$errno = '';$errstr = '';$timeout = 30; ...
- Redis入门与实践(附项目真实案例代码)
我是3y,一年CRUD经验用十年的markdown程序员常年被誉为优质八股文选手 今天继续更新austin项目,如果还没看过该系列的同学可以点开我的历史文章回顾下,在看的过程中不要忘记了点赞哟!建议 ...
- Java邮件发送中的setRecipient方法使用
一.方法setRecipient(Message.RecipientType type, Address address),是用于设置邮件的接收者. 1.有两个参数,第一个参数是接收者的类型,第二 ...
- 实例详解 Java 死锁与破解死锁
锁和被保护资源之间的关系 我们把一段需要互斥执行的代码称为临界区.线程在进入临界区之前,首先尝试加锁 lock(),如果成功,则进入临界区,此时我们称这个线程持有锁:否则呢就等待,直到持有锁的线程解锁 ...
- 传输层 lcx实现本地端口映射&&内网代理
如果目标服务器由于防火墙的限制,部分端口(例如3389)的数据无法通过防火墙,可以将目标服务器相应端口的数据透传到防火墙允许的端口(例如53),在目标主机上执行如下命令,就可以直接从远程桌面连接目标主 ...