linux用户层驱动-uio

UIO(Userspace I/O)是运行在用户空间的I/O技术。UIO适合在编写大型驱动程序的时候使用,它免去了频繁的内核模块的切换与重启。另外某些情况下性能也比内核驱动好,比如典型的应用例子就是dpdk。除了实现用户态驱动以外UIO也适合在虚拟化的时候做设备透传,相较于VFIO也是一种不错的选择。

1.UIO的工作方式

设备驱动的编写无非是两件事情:
1.设备内存的读写
2.中断的响应

UIO实现了mmap,可以实现映射物理内存到虚拟内存供用户层读写。

中断的响应必须在内核进行,UIO在内核实现了很少一部分中断的处理,之后通知到用户空间。用户层只需要简单的阻塞在对 /dev/uioX的read()操作上。当设备产生中断时,read()操作立即返回。UIO 也实现了poll()系统调用,你可以使用 select()来等待中断的发生。select()有一个超时参数可以用来实现有限时间内等待中断。
对设备的控制还可以通过/sys/class/uio下的各个文件的读写来完成。你注册的uio设备将会出现在该目录下。 假如你的uio设备是uio0那么映射的设备内存文件出现在 /sys/class/uio/uio0/maps/mapX,对该文件的读写就是对设备内存的读写。

想要运行一个 UIO的程序需要以下几个步骤:
1.编写内核UIO驱动
2.卸载真实设备驱动
3.绑定设备到UIO驱动

UIO的使用需要先编写一个内核的驱动,之后通过sys下的接口将设备卸载后再挂载到UIO驱动上。下面先看一下一个简单的内核驱动的实现。

2.UIO内核驱动
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>

#include <linux/fs.h>
#include <linux/platform_device.h>
#include <linux/uio_driver.h>
#include <linux/slab.h> /* kmalloc, kfree */

struct uio_info uio_virtual_device_info = {
   .name = "myuio",
   .version = "1.0",
   .irq = UIO_IRQ_NONE,
   // .irq = UIO_IRQ_CUSTOM,
};

static int uio_virtual_device_drv_probe(struct platform_device *pdev)
{
   printk("uio_virtual_device_probe( %p)\n", pdev);
   uio_virtual_device_info.mem[0].addr = (unsigned long)kmalloc(1024,GFP_KERNEL);

   if(uio_virtual_device_info.mem[0].addr == 0)
       return -ENOMEM;
   uio_virtual_device_info.mem[0].memtype = UIO_MEM_LOGICAL;
   uio_virtual_device_info.mem[0].size = 1024;

   printk("[%s,%d] uio_virtual_device_info.mem[0].addr:0x%x,.size :%lu\n",\
            __func__,__LINE__,uio_virtual_device_info.mem[0].addr,\
            uio_virtual_device_info.mem[0].size);

   if(uio_register_device(&pdev->dev, &uio_virtual_device_info))
       return -ENODEV;

   return 0;
}

static int uio_virtual_device_drv_remove(struct platform_device *pdev)
{
   uio_unregister_device(&uio_virtual_device_info);

   return 0;
}

static struct platform_driver virtual_device_drv = {
   .probe  = uio_virtual_device_drv_probe,
   // .remove = __devexit_p(uio_virtual_device_drv_remove),
   .remove = uio_virtual_device_drv_remove,
   .driver = {
       .name = "VIRTUAL_DEVICE",
       .owner = THIS_MODULE,
   }
};

static void virtual_device_remove(struct device *dev)
{

}

static struct platform_device virtual_device = {
   .name           = "VIRTUAL_DEVICE",
   .id             = -1,
   .dev            = {
   .release  = virtual_device_remove,
   },
};

static int __init uio_virtual_device_init(void)
{
   printk("virtual_device init ok!\n");
   platform_device_register(&virtual_device);

   printk("virtual_device_drv init ok!\n");
   return platform_driver_register(&virtual_device_drv);
}

static void __exit uio_virtual_device_exit(void)
{
   printk("Virtual_device remove ok!\n");
   platform_device_unregister(&virtual_device);

   printk("virtual_device_drv remove ok!\n");
   platform_driver_unregister(&virtual_device_drv);
}

module_init(uio_virtual_device_init);
module_exit(uio_virtual_device_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("ZP1015");
MODULE_DESCRIPTION("Demon of UIO");

这里使用了一个虚拟的设备代替真实设备,所以模块一插入就能初始化好UIO驱动,用户太就能直接操作。

3.UIO 内核驱动的绑定

这里顺带提一下sys下pci设备的各种ID目录

/sys/bus/pci/devices/地址/vendor
/sys/bus/pci/devices/地址/device
/sys/bus/pci/devices/地址/subsystem_vendor
/sys/bus/pci/devices/地址/subsystem_device

根据id可以匹配自己想匹配的设备,这里就暂时不用真实设备了,设备的解绑和绑定都不需要。

4.UIO user驱动
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <string.h>

#define UIO_DEV "/dev/uio0"
#define UIO_ADDR "/sys/class/uio/uio0/maps/map0/addr"
#define UIO_SIZE "/sys/class/uio/uio0/maps/map0/size"

static char uio_addr_buf[16], uio_size_buf[16];

int main()
{
  int uio_fd, addr_fd, size_fd;
  int uio_size;
  void* uio_addr, *access_address;

  uio_fd = open(UIO_DEV, O_RDWR);
  addr_fd = open(UIO_ADDR, O_RDONLY);
  size_fd = open(UIO_SIZE, O_RDONLY);
  if( addr_fd < 0 || size_fd < 0 || uio_fd < 0) {
       fprintf(stderr, "mmap: %s\n", strerror(errno));
       exit(-1);
  }
  read(addr_fd, uio_addr_buf, sizeof(uio_addr_buf));
  read(size_fd, uio_size_buf, sizeof(uio_size_buf));

  uio_addr = (void *)strtoul(uio_addr_buf, NULL, 0);
  uio_size = (int)strtol(uio_size_buf, NULL, 0);

  access_address = mmap(NULL, uio_size, PROT_READ | PROT_WRITE,
                     MAP_SHARED, uio_fd, 0);

  if (access_address == (void*) -1) {
      fprintf(stderr, "mmap: %s\n", strerror(errno));
      exit(-1);
  }
  printf("The device address %p (lenth %d)\n"
         "can be accessed over\n"
         "logical address %p\n", uio_addr, uio_size, access_address);

  return 0;
}

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: DPDK (Data Plane Development Kit) 是一个开源的数据平面开发工具包。它可以提供高性能的网络 I/O 接口,允许开发人员在用户空间中运行网络应用程序。 igb_uio 是 DPDK 提供的一种用于 Intel 82580/I350 以太网控制器的用户空间驱动程序。要使用 igb_uio 驱动,需要进行以下步骤: 1. 下载 DPDK 并解压缩。 2. 运行 "make config T=x86_64-native-linuxapp-gcc" 来配置 DPDK。 3. 在 .config 文件中找到并启用 "CONFIG_RTE_LIBRTE_IGB_UIO=y" 选项。 4. 运行 "make" 来编译 DPDK。 5. 运行 "make install" 来安装 DPDK。 6. 加载 igb_uio 驱动,运行 "modprobe uio" 和 "insmod build/kmod/igb_uio.ko"。 7. 将网卡绑定到 igb_uio 驱动上,运行 "./usertools/dpdk-devbind.py --bind=igb_uio 网卡名" 在完成这些步骤后,就可以在 DPDK 中使用 igb_uio 驱动了。 注意: - 上面的步骤基于linux系统,在其他系统上安装配置步骤可能有所不同 - 具体操作请参考DPDK官网,这里给出大致流程,需要结合具体DPDK版本参考 ### 回答2: 在DPDK中使用igb_uio驱动需要进行以下步骤: 1. 下载DPDK源代码:首先需要到DPDK官网(https://www.dpdk.org/)下载最新的DPDK源代码。 2. 解压源代码:将下载好的源代码文件解压到一个合适的目录下。 3. 配置编译环境:进入解压后的DPDK源代码目录,在终端中执行命令“make config T=x86_64-native-linuxapp-gcc”配置编译环境。其中,T参数根据自己的处理器架构进行选择,x86_64代表64位。 4. 编译DPDK:继续在终端中执行命令“make”编译DPDK。这一步需要耐心等待编译完成。 5. 设置环境变量:在终端中执行命令“export RTE_SDK=/path/to/dpdk”和“export RTE_TARGET=x86_64-native-linuxapp-gcc”分别设置DPDK的根目录和目标平台。 6. 下载igb_uio驱动:在终端中执行命令“make install T=x86_64-native-linuxapp-gcc”下载igb_uio驱动。这一步会自动从DPDK的软件仓库中下载igb_uio驱动,并将其安装到系统中。 7. 配置驱动:在终端中执行命令“modprobe uio”加载uio驱动,然后执行命令“insmod /path/to/dpdk/x86_64-native-linuxapp-gcc/kmod/igb_uio.ko”加载igb_uio驱动。 8. 绑定网卡:执行命令“dpdk-devbind --bind=igb_uio ethX”将指定的网卡绑定到igb_uio驱动。 至此,igb_uio驱动就成功下载、编译、配置完毕。现在可以在DPDK中使用igb_uio驱动来进行高性能网络应用开发了。 ### 回答3: DPDK(Data Plane Development Kit)是一种用于快速数据包处理的开源工具集。在DPDK中,igb_uio是一种用户UIO(Userspace Input/Output)驱动,用于将网卡设备映射到用户进程,实现零拷贝和更高的性能。 要下载、编译和配置igb_uio驱动,可以按照以下步骤进行: 1. 首先,确保系统安装了必要的构建工具和依赖项。例如,gcc、make、kernel-headers等。如果缺少相关软件包,可以使用包管理器进行安装。 2. 接下来,下载DPDK源代码。可以从DPDK官方网站(https://www.dpdk.org/)或者DPDK的GitHub仓库中获取最新的源代码。 3. 解压源代码包,并进入解压后的目录。 4. 在终端中,执行以下命令编译DPDK和igb_uio驱动: ``` make config T=x86_64-native-linuxapp-gcc make ``` 这将根据系统架构编译DPDK和igb_uio驱动的二进制文件。 5. 编译完成后,可以使用以下命令将igb_uio驱动安装到系统中: ``` sudo make install T=x86_64-native-linuxapp-gcc ``` 此命令将igb_uio.ko模块复制到适当的系统目录中。 6. 配置igb_uio驱动,使其可以加载并与网卡设备关联。需要编辑DPDK的配置文件(config文件),将CONFIG_RTE_EAL_IGB_UIO=y设置为解除注释,并保存更改。 7. 加载igb_uio驱动模块,可以使用以下命令: ``` sudo modprobe igb_uio ``` 如果成功加载,可以通过执行以下命令检查igb_uio模块是否成功绑定到网卡设备: ``` sudo ./dpdk-devbind.py --status ``` 此命令将显示网卡设备及其绑定状。 通过按照以上步骤进行,可以成功下载、编译和配置DPDK下的igb_uio驱动。完成后,可以在DPDK应用程序中使用igb_uio驱动来进行高性能的数据包处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值