调用Linux内核模块中的可执行文件。

huangapple go评论81阅读模式
英文:

Call a executable from Linux Kernel Module

问题

I am trying to call a executable from Linux Kernel Module, which is a interrupt service routine.

  1. I created a GPIO interrupt service routine, compiled and created a gpio_irq.ko file.
#include <linux/module.h>
#include <linux/init.h>
#include <linux/gpio.h>
#include <linux/interrupt.h>

/* Meta Information */
MODULE_LICENSE("GPL");
/* Reference code is taken from here */
MODULE_AUTHOR("Johannes 4 GNU/Linux");
MODULE_DESCRIPTION("A simple LKM for a gpio interrupt");

/** variable contains pin number o interrupt controller to which GPIO 499 is mapped to */
unsigned int irq_number;
unsigned int toggle_value = 0;
/**
 * Interrupt service routine is called, when interrupt is triggered
 */
static irq_handler_t gpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs) {
    printk("gpio_irq: Interrupt was triggered and ISR was called!\n");
    
    if (toggle_value == 0)
    {
        toggle_value = 1;
        if(gpio_direction_output(498, 1)) {
            printk("Error!\nCan not set GPIO 498 output value to 1!\n");
            gpio_free(498);
        }
    }
    
    if (toggle_value == 1)
    {
        toggle_value = 0;
        if(gpio_direction_output(498, 0)) {
            printk("Error!\nCan not set GPIO 498 output value to 0!\n");
            gpio_free(498);
        }
    }
    return (irq_handler_t) IRQ_HANDLED; 
}

/**
 * This function is called, when the module is loaded into the kernel
 */
static int __init ModuleInit(void) {
    printk("qpio_irq: Loading module... ");

    /* Setup the gpio */
    if(gpio_request(499, "rpi-gpio-499")) {
        printk("Error!\nCan not allocate GPIO 499\n");
        return -1;
    }
    if(gpio_request(498, "rpi-gpio-498")) {
        printk("Error!\nCan not allocate GPIO 498\n");
        return -1;
    }

    /* Set GPIO direction */
    if(gpio_direction_input(499)) {
        printk("Error!\nCan not set GPIO 499 to input!\n");
        gpio_free(499);
        return -1;
    }

    /* Setup the interrupt */
    irq_number = gpio_to_irq(499);

    if(request_irq(irq_number, (irq_handler_t) gpio_irq_handler, IRQF_TRIGGER_RISING, "my_gpio_irq", NULL) != 0){
        printk("Error!\nCan not request interrupt nr.: %d\n", irq_number);
        gpio_free(499);
        return -1;
    }

    printk("Done!\n");
    printk("GPIO 499 is mapped to IRQ Nr.: %d\n", irq_number);
    return 0;
}

/**
 * This function is called, when the module is removed from the kernel
 */
static void __exit ModuleExit(void) {
    printk("gpio_irq: Unloading module... ");
    free_irq(irq_number, NULL);
    gpio_free(499);
    gpio_free(498);
}

module_init(ModuleInit);
module_exit(ModuleExit);
  1. Loaded that .ko file to linux kernel using sudo insmod gpio_irq.ko

  2. With this, I am able to get interrupt and service the routine.

But,
I also want to call another executable from static irq_handler_t gpio_irq_handler(...) which is located at /home/user_name/Documents/

I know that, this can be done using system() call as explained in here

But, I am unable add <#include <stdlib.h> in my Linux Kernel Module. Compiler is throwing error saying that "Fatal Error: stdlib : No such file or directory"

Can someone guide me on how to call executable from Linux Kernel Moudule?

英文:

I am trying to call a executable from Linux Kernel Module, which is a interrupt service routine.

  1. I created a GPIO interrupt service routine, compiled and created a gpio_irq.ko file.
#include &lt;linux/module.h&gt;
#include &lt;linux/init.h&gt;
#include &lt;linux/gpio.h&gt;
#include &lt;linux/interrupt.h&gt;
/* Meta Information */
MODULE_LICENSE(&quot;GPL&quot;);
/* Reference code is taken from here */
MODULE_AUTHOR(&quot;Johannes 4 GNU/Linux&quot;);
MODULE_DESCRIPTION(&quot;A simple LKM for a gpio interrupt&quot;);
/** variable contains pin number o interrupt controller to which GPIO 499 is mapped to */
unsigned int irq_number;
unsigned int toggle_value = 0;
/**
* Interrupt service routine is called, when interrupt is triggered
*/
static irq_handler_t gpio_irq_handler(unsigned int irq, void *dev_id, struct pt_regs *regs) {
printk(&quot;gpio_irq: Interrupt was triggered and ISR was called!\n&quot;);
if (toggle_value == 0)
{
toggle_value = 1;
if(gpio_direction_output(498, 1)) {
printk(&quot;Error!\nCan not set GPIO 498 output value to 1!\n&quot;);
gpio_free(498);
}
}
if (toggle_value == 1)
{
toggle_value = 0;
if(gpio_direction_output(498, 0)) {
printk(&quot;Error!\nCan not set GPIO 498 output value to 0!\n&quot;);
gpio_free(498);
}
}
return (irq_handler_t) IRQ_HANDLED; 
}
/**
* This function is called, when the module is loaded into the kernel
*/
static int __init ModuleInit(void) {
printk(&quot;qpio_irq: Loading module... &quot;);
/* Setup the gpio */
if(gpio_request(499, &quot;rpi-gpio-499&quot;)) {
printk(&quot;Error!\nCan not allocate GPIO 499\n&quot;);
return -1;
}
if(gpio_request(498, &quot;rpi-gpio-498&quot;)) {
printk(&quot;Error!\nCan not allocate GPIO 498\n&quot;);
return -1;
}
/* Set GPIO direction */
if(gpio_direction_input(499)) {
printk(&quot;Error!\nCan not set GPIO 499 to input!\n&quot;);
gpio_free(499);
return -1;
}
/* Setup the interrupt */
irq_number = gpio_to_irq(499);
if(request_irq(irq_number, (irq_handler_t) gpio_irq_handler, IRQF_TRIGGER_RISING, &quot;my_gpio_irq&quot;, NULL) != 0){
printk(&quot;Error!\nCan not request interrupt nr.: %d\n&quot;, irq_number);
gpio_free(499);
return -1;
}
printk(&quot;Done!\n&quot;);
printk(&quot;GPIO 499 is mapped to IRQ Nr.: %d\n&quot;, irq_number);
return 0;
}
/**
* This function is called, when the module is removed from the kernel
*/
static void __exit ModuleExit(void) {
printk(&quot;gpio_irq: Unloading module... &quot;);
free_irq(irq_number, NULL);
gpio_free(499);
gpio_free(498);
}
module_init(ModuleInit);
module_exit(ModuleExit);
  1. Loaded that .ko file to linux kernel using sudo insmod gpio_irq.ko

  2. With this, I am able to get interrupt and service the routine.

But,
I also want to call another executable from static irq_handler_t gpio_irq_handler(...) which is located at /home/user_name/Documents/

I know that, this can be done using system() call as explained in here

But, I am unable add &lt;#include &lt;stdlib.h&gt; in my Linux Kernel Module. Compiler is throwing error saying that "Fatal Error: stdlib : No such file or directory"

Can someone guide me on how to call executable from Linux Kernel Moudule?

答案1

得分: 3

你的方法存在问题,因为加载和运行可执行文件需要许多系统调用和中断。你无法在中断例程内部执行这些操作,因为中断被禁用。

第二个原因是C运行时库,包括stdlib.h中的所有内容,都是用户空间库,不在内核中可用。

第三个原因是加载和运行可执行文件非常耗时,这正是你想要解决的问题。

幸运的是,多年前就开发出了一种简单的方法来解决你的问题,即在中断和执行用户空间任务之间最小化延迟。

启动你的用户空间进程,这样可以摆脱所有启动开销,然后发出一个read调用到你的内核模块。这将阻塞,直到你的模块响应。读取操作可以返回一个表示状态的单个字节。读取响应的延迟远远小于启动可执行文件(如果这是可能的话)。

英文:

The problem with your approach is that to load and run an executable requires many syscalls and interrupts. You can't do this from inside an interrupt routine since interrupts are disabled.

A second reason is that the C runtime, including everything in stdlib.h, is a user-space library. None of it is available in the kernel.

A third reason is that loading and running an executable is time-consuming, which is the problem that you want to solve.

Fortunately, there is a simple method developed years ago to solve your problem of minimizing latency between your interrupt and execution of the user-space task.

Start your user space process, which gets all of the startup overhead out of the way, then issue a read call to your kernel module. This will block until your module responds. The read could return a single byte indicating status. The latency of the read response will be far less than starting an executable (if it were even possible).

huangapple
  • 本文由 发表于 2023年6月25日 19:47:25
  • 转载请务必保留本文链接:https://go.coder-hub.com/76550236.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定