Linux内核 -- UIO (User-space I/O) 简介与使用笔记

UIO (User-space I/O) 简介

UIO (User-space I/O) 是 Linux 内核提供的一种机制,用于简化设备驱动的开发。它将设备的硬件资源(如内存映射、中断等)通过简单的接口暴露给用户空间程序,从而使用户可以在用户空间编写复杂的设备逻辑,而内核只需完成基础的资源管理工作。


内核态作用与实现

UIO 内核态的作用
  1. 硬件资源管理
    • 提供设备内存映射支持,将设备寄存器或内存映射到用户空间。
    • 注册和处理硬件中断(可选)。
  2. 中断通知
    • 将设备硬件中断转发给用户空间程序。
UIO 内核态的实现步骤
  1. 定义设备信息结构
    使用 struct uio_info 定义设备信息,包括中断号、内存地址等。

    static struct uio_info my_uio_info = {
        .name = "my_device",
        .version = "1.0",
        .irq = 42,                      // 中断号(若不需要中断,可设置为 UIO_IRQ_NONE)
        .irq_flags = IRQF_SHARED,       // 中断标志
        .handler = my_irq_handler,      // 中断处理函数(可选)
        .mem[0].addr = 0x40000000,      // 物理地址
        .mem[0].size = 0x1000,          // 内存大小
        .mem[0].memtype = UIO_MEM_PHYS, // 内存类型
    };
    
  2. 注册设备
    使用 uio_register_device 注册设备信息:

    static int __init my_uio_init(void) {
        return uio_register_device(NULL, &my_uio_info);
    }
    
    static void __exit my_uio_exit(void) {
        uio_unregister_device(&my_uio_info);
    }
    
    module_init(my_uio_init);
    module_exit(my_uio_exit);
    MODULE_LICENSE("GPL");
    
  3. 实现中断处理函数(可选)
    如果需要支持硬件中断,需要实现中断处理逻辑:

    static irqreturn_t my_irq_handler(int irq, struct uio_info *dev_info) {
        return IRQ_HANDLED; // 通知内核中断已处理
    }
    
注意事项
  • 如果设备不需要中断功能,可以将 irq 设置为 UIO_IRQ_NONE,并省略 handler
  • 内核态代码只需要完成资源管理工作,具体设备逻辑由用户空间程序完成。

用户态作用与实现

UIO 用户态的作用
  1. 设备访问:通过 /dev/uioX 文件与设备交互。
  2. 内存映射:使用 mmap 将设备内存映射到用户空间,直接操作设备寄存器。
  3. 中断处理:通过 read 调用等待中断事件。
用户态的实现步骤
  1. 打开设备文件

    int fd = open("/dev/uio0", O_RDWR);
    if (fd < 0) {
        perror("Failed to open /dev/uio0");
        return -1;
    }
    
  2. 内存映射
    使用 mmap 将设备内存映射到用户空间:

    void *reg_base = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (reg_base == MAP_FAILED) {
        perror("Failed to mmap");
        close(fd);
        return -1;
    }
    
  3. 处理中断
    通过 read 等待中断事件:

    unsigned int irq_count;
    while (1) {
        read(fd, &irq_count, sizeof(irq_count));
        printf("Interrupt received! Count: %d\n", irq_count);
    }
    
  4. 释放资源
    在程序结束时,释放映射的内存并关闭设备:

    munmap(reg_base, 0x1000);
    close(fd);
    

示例代码

内核态代码

以下是一个完整的内核态代码示例:

#include <linux/module.h>
#include <linux/uio_driver.h>

static irqreturn_t my_irq_handler(int irq, struct uio_info *dev_info) {
    return IRQ_HANDLED;
}

static struct uio_info my_uio_info = {
    .name = "my_device",
    .version = "1.0",
    .irq = 42,
    .irq_flags = IRQF_SHARED,
    .handler = my_irq_handler,
    .mem[0].addr = 0x40000000,
    .mem[0].size = 0x1000,
    .mem[0].memtype = UIO_MEM_PHYS,
};

static int __init my_uio_init(void) {
    return uio_register_device(NULL, &my_uio_info);
}

static void __exit my_uio_exit(void) {
    uio_unregister_device(&my_uio_info);
}

module_init(my_uio_init);
module_exit(my_uio_exit);
MODULE_LICENSE("GPL");
用户态代码

以下是对应的用户态代码示例:

#include <fcntl.h>
#include <stdio.h>
#include <sys/mman.h>
#include <unistd.h>

int main() {
    int fd = open("/dev/uio0", O_RDWR);
    if (fd < 0) {
        perror("Failed to open /dev/uio0");
        return -1;
    }

    void *reg_base = mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (reg_base == MAP_FAILED) {
        perror("Failed to mmap");
        close(fd);
        return -1;
    }

    unsigned int irq_count;
    while (1) {
        read(fd, &irq_count, sizeof(irq_count));
        printf("Interrupt received! Count: %d\n", irq_count);
    }

    munmap(reg_base, 0x1000);
    close(fd);
    return 0;
}

注意事项

  1. 中断功能
    • 如果不需要中断功能,可以省略中断处理函数,并将 irq 设置为 UIO_IRQ_NONE
  2. 性能问题
    • 使用 UIO 时,中断和用户空间之间的切换会增加延迟,不适合高实时性场景。
  3. 安全性
    • UIO 将设备的硬件资源直接映射到用户空间,需确保用户空间程序的安全性,以防止资源滥用。

总结

UIO 是一种简化设备驱动开发的高效工具,适合处理简单设备或快速原型开发。在内核态中,开发者只需完成资源注册和中断处理(可选);在用户态中,程序通过 /dev/uioX 文件与设备交互,完成具体逻辑。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值