Search code examples
linuxlinux-kerneldriver

Getting "returned with preemption imbalance" error for a simple linux driver


I have written a simple driver which is supposed to check if VMX is enabled or not, and the code for that is below.

#include <linux/module.h>
#include <linux/init.h>
inline bool vmxSupport(void)
{

        int getVmxSupport, vmxBit;
        __asm__  ("mov $1, %rax");
        __asm__  ("cpuid");
        __asm__  ("mov %%ecx , %0\n\t":"=r" (getVmxSupport));
        //pr_info("\n");
        vmxBit = (getVmxSupport >> 5) & 1;
        if (vmxBit == 1){
                return true;
        }
        else {
                return false;
        }
}

static int __init my_init(void)
{

        vmxSupport();
        pr_info("Hello world from mod1\n");
        return 0;
}

static void __exit my_exit(void)
{
        pr_info("Goodbye world from mod1\n");
}

module_init(my_init);
module_exit(my_exit);

MODULE_AUTHOR("vpn");
MODULE_DESCRIPTION("module1.c");
MODULE_LICENSE("GPL v2");

Short snippet of the error i'm getting:

Hello world from mod1
[  908.381100] ------------[ cut here ]------------
[  908.389199] initcall my_init+0x0/0x1000 [module1] returned with preemption imbalance
[  908.396171] WARNING: CPU: 1 PID: 5049 at init/main.c:1300 do_one_initcall+0x2b8/0x320
[  908.401424] Modules linked in: module1(OE+) intel_rapl_msr(E) intel_rapl_common(E)
.
.
.
 R10: 0000000000000003 R11: 0000000000000246 R12: 0000559e223dc260
[  908.560509] R13: 0000000000000000 R14: 0000559e235ec750 R15: 0000000000000000
[  908.562768] ---[ end trace 0d070b847da4cd90 ]---
[  908.565107] BUG: scheduling while atomic: insmod/5049/0x01000800

But when I add a pr_info(remove the comment from the shared code) after the 3rd __asm__ i don't get this issue. Things i have tried:

  • Disable optimization for the function vmxSupport
  • inline / uninline the vmxSupport function
  • Checked the disassembly, i don't see anything crazy.

Any idea why I'm getting this error?


Solution

  • "Cpuid" alters RBX, RCX, and RDX registers. I suggest you to save them (push) before, and restore them (pop) after the instruction, because the compiler assumes that some of them are preserved. Your problem is probably due to a side effect of altering registers.