从 Linux 内核模块中调用用户空间函数

标签 c linux linux-kernel driver linux-device-driver

我正在编写一个简单的 Linux 字符设备驱动程序,通过 I/O 端口将数据输出到硬件。我有一个函数可以执行浮点运算来计算硬件的正确输出;不幸的是,这意味着我需要将这个函数保留在用户空间中,因为 Linux 内核不能很好地处理浮点运算。

这是设置的伪表示(请注意,这段代码没有做任何具体的事情,它只是显示了我的代码的相对布局):

用户空间函数:

char calculate_output(char x){
    double y = 2.5*x;
    double z = sqrt(y);
    
    char output = 0xA3;

    if(z > 35.67){
        output = 0xC0;
    }
    
    return output;
}

内核空间代码:

unsigned i;
for(i = 0; i < 300; i++){
    if(inb(INPUT_PORT) & NEED_DATA){
        char seed = inb(SEED_PORT);
        char output = calculate_output(seed);
        outb(output, OUTPUT_PORT);
    }

    /* do some random stuff here */
}

我考虑过使用 ioctl 从用户空间函数传入数据,但我不确定如何处理函数调用处于循环中并且更多代码在下一次调用 calculate_output 发生。

我设想的工作方式是:

  1. 主用户空间程序将启动内核空间代码(可能通过ioctl)
  2. 用户空间程序阻塞并等待内核空间代码
    • 内核空间程序请求用户空间程序输出数据,并阻止等待
    • 用户空间程序解除阻塞,计算并发送数据(ioctl?),然后再次阻塞
    • 内核空间程序解锁并继续
  3. 内核空间程序完成并通知用户空间
  4. 用户空间解锁并继续下一个任务

那么我如何在内核空间和用户空间之间进行通信,并进行阻塞,这样我就不会让用户空间不断轮询设备文件以查看它是否需要发送数据?


注意:虽然定点运算在我的示例代码中运行良好,但在实际代码中不是一个选项;我需要 float 提供的大范围——即使没有——我担心重写代码以使用定点运算会使 future 的维护者混淆算法。

最佳答案

我认为最简单的解决方案是在您的内核驱动程序中创建一个字符设备,并使用您自己的虚拟文件文件操作。然后用户空间可以打开这个设备O_RDWR .您必须实现两个主要的文件操作:

  • read -- 这就是内核将数据传回用户空间的方式。此函数在调用 read() 的用户空间线程的上下文中运行系统调用,在你的情况下,它应该阻塞,直到内核有另一个它需要知道输出的种子值。

  • write -- 这就是用户空间将数据传递到内核的方式。在您的情况下,内核只会获取对先前读取的响应并将其传递给硬件。

然后你在用户空间中得到一个简单的循环:

while (1) {
    read(fd, buf, sizeof buf);
    calculate_output(buf, output);
    write(fd, output, sizeof output);
}

而且内核中根本没有循环——一切都在驱动事物的用户空间进程的上下文中运行,内核驱动程序只负责将数据移入/移出硬件。

根据您在内核端“在这里做一些随机的事情”是什么,可能无法如此简单地做到这一点。如果你真的需要内核循环,那么你需要创建一个内核线程来运行那个循环,然后在 input_data 的行中有一些变量。 , input_ready , output_dataoutput_ready ,以及几个等待队列和您需要的任何锁定。

内核线程读取数据的时候,你把数据放在input_ready里面并设置 input_ready标记并向输入等待队列发送信号,然后执行 wait_event(<output_ready is set>) . read文件操作会执行 wait_event(<input_ready is set>)并在准备就绪时将数据返回给用户空间。同样的 write文件操作将从用户空间获取的数据放入output_data并设置 output_ready并向输出等待队列发送信号。

另一种(更丑陋,更不便携)的方法是使用类似 ioperm 的东西, iopl/dev/port完全在用户空间中完成所有操作,包括低级硬件访问。

关于从 Linux 内核模块中调用用户空间函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16067902/

相关文章:

c - free() : invalid next size (normal) on fclose. 但当 Valgrind 运行时不会

c - 从 CD-ROM 快速读取数据

c++ - 如何让这个 getnameinfo 代码工作

linux - 用于检查 sybase iq 状态的 shell 脚本

linux - 字符设备的动态注册为我的字符设备分配了与 Documentation/devices.txt 不对应的主编号。这是为什么?

git - 在我的 repo 协议(protocol)中,最长的哈希前缀必须有多长才能防止重叠?

c - 列出并查看 gcc C11 头文件

c - 受制于结构、获取和放置

python - 如何在 linux 上安装 tensorflow 0.10.0?

linux - 没有IP的后台进程会受到键盘输入的影响吗?