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

 2025-06-13 10:33:42    286  

UIO (User-space I/O) 简介

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

内核态作用与实现

UIO 内核态的作用

硬件资源管理:

提供设备内存映射支持,将设备寄存器或内存映射到用户空间。注册和处理硬件中断(可选)。 中断通知:

将设备硬件中断转发给用户空间程序。

UIO 内核态的实现步骤

定义设备信息结构 使用 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, // 内存类型

};

注册设备 使用 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");

实现中断处理函数(可选) 如果需要支持硬件中断,需要实现中断处理逻辑:

static irqreturn_t my_irq_handler(int irq, struct uio_info *dev_info) {

return IRQ_HANDLED; // 通知内核中断已处理

}

注意事项

如果设备不需要中断功能,可以将 irq 设置为 UIO_IRQ_NONE,并省略 handler。内核态代码只需要完成资源管理工作,具体设备逻辑由用户空间程序完成。

用户态作用与实现

UIO 用户态的作用

设备访问:通过 /dev/uioX 文件与设备交互。内存映射:使用 mmap 将设备内存映射到用户空间,直接操作设备寄存器。中断处理:通过 read 调用等待中断事件。

用户态的实现步骤

打开设备文件

int fd = open("/dev/uio0", O_RDWR);

if (fd < 0) {

perror("Failed to open /dev/uio0");

return -1;

}

内存映射 使用 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;

}

处理中断 通过 read 等待中断事件:

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);

示例代码

内核态代码

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

#include

#include

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

#include

#include

#include

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;

}

注意事项

中断功能:

如果不需要中断功能,可以省略中断处理函数,并将 irq 设置为 UIO_IRQ_NONE。 性能问题:

使用 UIO 时,中断和用户空间之间的切换会增加延迟,不适合高实时性场景。 安全性:

UIO 将设备的硬件资源直接映射到用户空间,需确保用户空间程序的安全性,以防止资源滥用。

总结

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


百度网盘创建共享文件夹,邀请别人一起上传文件
目前最好最有效的三种【祛除疤痕】的方法推荐
友情链接