Pregunta

I need to reboot upon handling an IRQ in kernel land.

I want to call the /sbin/reboot binary, but I have got limitations due to the IRQ scope.

Code follows :

#define MY_IRQ_ID       42

void __init             rebootmodule_init(void) {
    request_any_context_irq(MY_IRQ_ID, rebootmodule_irq_handler, IRQF_TRIGGER_FALLING, "irq-name", NULL);
}

irqreturn_t             rebootmodule_irq_handler(int irq, void *dev_id) {
    my_reboot();
    return IRQ_HANDLED;
}

void                    my_reboot(void) {
    int                 ret;
    char                *argv[2], *envp[4];

    argv[0] = "/sbin/reboot";
    argv[1] = NULL;
    envp[0] = "HOME=/";
    envp[1] = "PWD=/";
    envp[2] = "PATH=/sbin";
    envp[3] = NULL;
    ret = call_usermodehelper(argv[0], argv, envp, 0);
    printk(KERN_INFO "trying to reboot (ret = %d)", ret);
}

I can see the printk(...) when the IRQ is triggered but I have some errors, even if I replace /sbin/reboot by /bin/rm /tmp/its-not-working.

I tested other way to do reboot like mvBoardReset(), machine_halt(), arm_pm_restart(), pm_power_off(), kill(1, SIGTSTP), reboot(), handle_sysrq('b'), I always have errors that I don't have outside the IRQ scope.

I really want to call /sbin/reboot, since it does clean soft reset.

Thank you for your time.

¿Fue útil?

Solución

Just an idea: you can start kernel thread by kthread_run(), put it to sleep by wait_event(), wake it up in the IRQ handler by wake_up(), do your stuff (run /sbin/reboot or whatever you want) in the kernel thread. Something like this (completely untested):

#define MY_IRQ_ID 42

static DECLARE_WAIT_QUEUE_HEAD(wq);
static volatile int showtime = 0;

void my_reboot(void) {
    int ret;
    char *argv[2], *envp[4];

    argv[0] = "/sbin/reboot";
    argv[1] = NULL;
    envp[0] = "HOME=/";
    envp[1] = "PWD=/";
    envp[2] = "PATH=/sbin";
    envp[3] = NULL;
    ret = call_usermodehelper(argv[0], argv, envp, 0);
    printk(KERN_INFO "trying to reboot (ret = %d)", ret);
}

static int my_thread(void *arg) {
    wait_event(&wq, showtime);
    my_reboot();
    return 0;
}

irqreturn_t rebootmodule_irq_handler(int irq, void *dev_id) {
    showtime = 1;
    wake_up(&wq);
    return IRQ_HANDLED;
}

void __init rebootmodule_init(void) {
    kthread_run(my_thread, NULL, "my_module");
    request_any_context_irq(MY_IRQ_ID, rebootmodule_irq_handler, IRQF_TRIGGER_FALLING, "irq-name", NULL);
}

Don't forget to handle module __exit and the case when interrupt has come before the kernel thread was sent to sleep.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top