title: Calling printk in a simple IRQ handler crashes the kernel
body: <p>I'm new to kernel programming and I couldn't find enough information to know why this happens. Basically I'm trying to replace the page fault handler in the kernel's IDT with something simple that calls the original handler in the end. I just want this function to print a notification that it is called, and calling <code>printk()</code> inside it always results in a kernel panic. It runs fine otherwise.</p>
  <pre class="lang-c prettyprint-override"><code>#include &lt;asm/desc.h&gt;
  #include &lt;linux/mm.h&gt;
  #include &lt;asm/traps.h&gt;
  #include &lt;linux/types.h&gt;
  #include &lt;linux/errno.h&gt;
  #include &lt;linux/sched.h&gt;
  #include &lt;asm/uaccess.h&gt;
  #include &lt;linux/module.h&gt;
  #include &lt;linux/kernel.h&gt;
  #include &lt;asm/desc_defs.h&gt;
  #include &lt;linux/moduleparam.h&gt;
  
  #define PAGEFAULT_INDEX 14
  
  
  // Old and new IDT registers
  static struct desc_ptr old_idt_reg, new_idt_reg;
  
  static __attribute__((__used__)) unsigned long old_pagefault_pointer, new_page;
  
  
  
  // The function that replaces the original handler
  asmlinkage void isr_pagefault(void);
  asm(&quot;    .text&quot;);
  asm(&quot;    .type isr_pagefault,@function&quot;);
  asm(&quot;isr_pagefault:&quot;);
  asm(&quot;    callq print_something&quot;);
  asm(&quot;    jmp *old_pagefault_pointer&quot;);
  
  
  
  void print_something(void) {
      // This printk causes the kernel to crash!
      printk(KERN_ALERT &quot;Page fault handler called\n&quot;);
  
      return;
  
  }
  
  void my_idt_load(void *ptr) {
      printk(KERN_ALERT &quot;Loading on a new processor...\n&quot;);
      load_idt((struct desc_ptr*)ptr);
  
      return;
  }
  
  
  
  int module_begin(void) {
  
      gate_desc *old_idt_addr, *new_idt_addr;
      unsigned long idt_length;
  
      store_idt(&amp;old_idt_reg);
  
      old_idt_addr = (gate_desc*)old_idt_reg.address;
      idt_length   = old_idt_reg.size;
  
      // Get the pagefault handler pointer from the IDT's pagefault entry
      old_pagefault_pointer = 0
          | ((unsigned long)(old_idt_addr[PAGEFAULT_INDEX].offset_high)   &lt;&lt; 32   )
          | ((unsigned long)(old_idt_addr[PAGEFAULT_INDEX].offset_middle) &lt;&lt; 16   )
          | ((unsigned long)(old_idt_addr[PAGEFAULT_INDEX].offset_low)            );
  
      printk(KERN_ALERT &quot;Saved pointer to old pagefault handler: %p\n&quot;, (void*)old_pagefault_pointer);
  
      // Allocate a new page for the new IDT
      new_page = __get_free_page(GFP_KERNEL);
      if (!new_page)
          return -1;
  
      // Copy the original IDT to the new page
      memcpy((void*)new_page, old_idt_addr, idt_length);
  
      // Set up the new IDT
      new_idt_reg.address = new_idt_addr = new_page;
      new_idt_reg.size = idt_length;
      pack_gate(
          &amp;new_idt_addr[PAGEFAULT_INDEX],
          GATE_INTERRUPT,
          (unsigned long)isr_pagefault, // The interrupt written in assembly at the start of the code
          0, 0, __KERNEL_CS
      );
  
      // Load the new table
      load_idt(&amp;new_idt_reg);
      smp_call_function(my_idt_load, (void*)&amp;new_idt_reg, 1); // Call load_idt on the rest of the cores
  
      printk(KERN_ALERT &quot;New IDT loaded\n\n&quot;);
  
      return 0;
  
      }
  
  void module_end(void) {
  
      printk( KERN_ALERT &quot;Exit handler called now. Reverting changes and exiting...\n\n&quot;);
  
      load_idt(&amp;old_idt_reg);
      smp_call_function(my_idt_load, (void*)&amp;old_idt_reg, 1);
  
      if (new_page)
          free_page(new_page);
  
  }
  
  module_init(module_begin);
  module_exit(module_end);
  </code></pre>
  <p>Many thanks to anyone who can tell me what I'm doing wrong here.</p>