从Linux内核模块中调用用户空间函数 [英] Call a userspace function from within a Linux kernel module

查看:478
本文介绍了从Linux内核模块中调用用户空间函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm programming a simple Linux character device driver to output data to a piece of hardware via I/O ports. I have a function which performs floating point operations to calculate the correct output for the hardware; unfortunately this means I need to keep this function in userspace since the Linux kernel doesn't handle floating point operations very nicely.

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

Here's a pseudo representation of the setup (note that this code doesn't do anything specific, it just shows the relative layout of my code):

用户空间功能:

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从用户空间函数中传递数据,但是我不确定如何处理该函数调用处于循环且在下一次调用发生.

I thought about using ioctl to pass in the data from the userspace function, but I'm not sure how to handle the fact that the function call is in a loop and more code executes before the next call to calculate_output occurs.

我设想这项工作的方式是:

The way I envision this working is:

  1. 主用户空间程序将启动内核空间代码(也许通过ioctl)
  2. 用户空间程序阻止并等待内核空间代码
    • 内核空间程序 asks 用户空间程序用于输出数据,并阻止等待
    • 用户空间程序取消阻止,计算并发送数据(ioctl?),然后再次阻止
    • 内核空间程序取消阻止并继续
  1. main userspace program will start the kernelspace code (perhaps via ioctl)
  2. userspace program blocks and waits for kernelspace code
    • kernelspace program asks userspace program for output data, and blocks to wait
    • userspace program unblocks, calculates and sends data (ioctl?), then blocks again
    • kernelspace program unblocks and continues

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

So how do I have the the communication between kernelspace and userspace, and also have blocking so that I don't have the userspace continually polling a device file to see if it needs to send data?

一个警告:虽然定点算术在我的示例代码中可以很好地工作,但在实际代码中不是一个选择;我需要浮点数提供的范围很广,而且即使没有,我也担心重写代码以使用定点算法会使将来的维护者感到困惑.

A caveat: while fixed point arithmetic would work quite well in my example code, it is not an option in the real code; I require the large range that floating point provides and -- even if not -- I'm afraid rewriting the code to use fixed point arithmetic would obfuscate the algorithm for future maintainers.

推荐答案

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

I think the simplest solution would be to create a character device in your kernel driver, with your own file operations for a virtual file. Then userspace can open this device O_RDWR. You have to implement two main file operations:

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

  • read -- this is how the kernel passes data back up to userspace. This function is run in the context of the userspace thread calling the read() system call, and in your case it should block until the kernel has another seed value that it needs to know the output for.

write-这是用户空间将数据传递到内核的方式.在您的情况下,内核仅将对先前读取的响应作为响应,并将其传递给硬件.

write-- this is how userspace passes data into the kernel. In your case, the kernel would just take the response to the previous read and pass it onto the hardware.

然后,您在用户空间中遇到一个简单的循环:

Then you end up with a simple loop in userspace:

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

内核完全没有循环-一切都在驱动事物的用户空间进程的上下文中运行,而内核驱动程序仅负责将数据移入/移出硬件.

and no loop at all in the kernel -- everything runs in the context of the userspace process that is driving things, and the kernel driver is just responsible for moving the data to/from the hardware.

取决于您在内核方面在这里做一些随机的事情"是什么,可能不可能这么简单地做到这一点.如果您确实需要内核循环,则需要创建一个内核线程来运行该循环,然后在input_datainput_readyoutput_dataoutput_ready中包含一些变量,以及一些等待队列以及您需要的任何锁定.

Depending on what your "do some random stuff here" on the kernel side is, it might not be possible to do it quite so simply. If you really need the kernel loop, then you need to create a kernel thread to run that loop, and then have some variables along the lines of input_data, input_ready, output_data and output_ready, along with a couple of waitqueues and whatever locking you need.

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

When the kernel thread reads data, you put the data in input_ready and set the input_ready flag and signal the input waitqueue, and then do wait_event(<output_ready is set>). The read file operation would do a wait_event(<input_ready is set>) and return the data to userspace when it becomes ready. Similarly the write file operation would put the data it gets from userspace into output_data and set output_ready and signal the output waitqueue.

另一种(较不便于使用,较不便于携带)的方法是使用iopermiopl/dev/port之类的东西来完全在用户空间中完成所有工作,包括低级别的硬件访问.

Another (uglier, less portable) way is to use something like ioperm, iopl or /dev/port to do everything completely in userspace, including the low-level hardware access.

这篇关于从Linux内核模块中调用用户空间函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆