0

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?

  • Do you think loading and running an executable might need to use interrupts? And might take a while? – stark Jun 25 '23 at 12:14
  • Yes. We need a very minimum delay between an even occurrence (gpio interrupt) and executing the service. – Aravind D. Chakravarti Jun 25 '23 at 12:23
  • 2
    You are doing something very unusual. Interrupt handlers should return extremely quickly, definitely faster than creating a process. – pts Jun 25 '23 at 13:53
  • Most of the latency will be caused by program startup. To get low latency, make sure your program is already running by the time the GPIO event happens. – pts Jun 25 '23 at 14:05
  • It's possible to start a new process from a kernel module, but not with userspace APIs like stdlib.h, system, popen, fork, exec... . – pts Jun 25 '23 at 14:14
  • Sounds like you are trying to do the tooth surgery starting from the bottom. Something very new in medicine. – 0andriy Jun 25 '23 at 19:05
  • @0andriy Ha ha.. Exactly! Either I will create a new technique or will be jailed :-D Anyway, jokes apart, I was able to do interrupt handling properly, see my response in comment below to Stark. – Aravind D. Chakravarti Jun 28 '23 at 07:02

1 Answers1

3

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

stark
  • 12,615
  • 3
  • 33
  • 50
  • Hi Stark, I used 'signals' between Linux Kernel Module and User Space application. Seems to be working. I referred [this] (https://github.com/Johannes4Linux/Linux_Driver_Tutorial/tree/main/15_Sending_Signals) repository. It seems to be working. – Aravind D. Chakravarti Jun 26 '23 at 10:32