[vox-tech] Fwd: Implementing interrupt handlers

Bill Kendrick nbs at sonic.net
Tue Dec 20 18:25:46 PST 2011


David posted this from an address that's not subscribed to the list.
Fwd'ing on his behalf.

-bill!


----- Forwarded message from vox-tech-bounces at lists.lugod.org -----

Date: Tue, 20 Dec 2011 08:03:54 -0800
From: vox-tech-bounces at lists.lugod.org
Subject: Auto-discard notification
To: vox-tech-owner at lists.lugod.org

The attached message has been automatically discarded.
Date: Tue, 20 Dec 2011 15:57:23 +0000
From: David Luengo López <olelen at gmail.com>
Subject: Implementing interrupt handlers
To: vox-tech at lists.lugod.org

   Hi everyone, let's see if you can help me.

   I'm trying to implement my own interrupt handler (why? because it's fun
   :). My idea right now is to install on the system a function like
   system_call() (you know, the handler of int $0x80), but on a free
   interrupt.

   First I tried by using the kernel function request_irq(), but when I look
   at the corresponding IDT entry there still was the ignore_int() function
   (you know, Linux sets all the interrupt handlers as ignore_int() and then
   it fills the handlers properly with ?init_traps()?). Am I wrong or should
   request_irq() write on IDT?.

   After failing with request_irq() I decided to write the changes on IDT by
   my own, so right now the changes on IDT are made by me (using a bit of
   kernel's help):

   /***
    * @n: The index on the IDT that should be rewritten.
    * @addr: The address of the new interrupt handler.
    */
   void setGate(unsigned int n, unsigned long addr) {
       gate_desc entry, *idt;
       struct desc_ptr idtr;

       // Code extracted from arch/x86/include/asm/desc.h, I prefer to have
   the
       // same notation.
       entry.a = (__KERNEL_CS << 16) | (addr & 0xffff);
       entry.b = (addr & 0xffff0000) |
                 ((0x80 | (RING3 << 5) | GATE_TRAP) << 8) |
                 0x00;

       native_store_idt(&idtr);
       idt = (gate_desc *)idtr.address;
       native_write_idt_entry(idt, n, &entry);
   }

   Here we have not the includes and defines needed but it is not hard to
   guess them (<asm/desc.h>, <asm/desc_defs.h>, define RING3 (3) if I still
   remember...).

   When I do it by my own the IDT is correctly rewritten but when i try to
   call that interrupt from user space context i got an error. Here you have
   the stupid program that generates the interrupt:

   .globl main
   main:
      int $<n>
      nop

   Where <n> is the vector of the interrupt I rewrote, usually interrupt 31.

   When I run this program the task got killed and the kernel wrote this
   message into /var/log/messages:

   ...: [17234.280005] *pde = 1d9dc067 *pte = 00000000
   ...: [17234.280005] Modules linked in: yarr loop snd_ens1371 gameport
   snd_rawmidi snd_seq_device snd_ac97_codec ac97_bus snd_pcm snd_timer snd
   i2c_piix4 soundcore shpchp snd_page_alloc pci_hotplug i2c_core parport_pc
   psmouse parport pcspkr serio_raw evdev container processor ac button ext3
   jbd mbcache sg sd_mod crc_t10dif sr_mod cdrom uhci_hcd ata_generic mptspi
   mptscsih ata_piix ehci_hcd mptbase libata thermal floppy pcnet32 mii
   usbcore nls_base scsi_transport_spi scsi_mod thermal_sys [last unloaded:
   yarr]
   ...: [17234.280005]
   ...: [17234.280005] Pid: 1772, comm: intr_poc Tainted: G      D W 
   (2.6.32-5-686 #1) VMware Virtual Platform
   ...: [17234.280005] EIP: 0060:[<e0ea32e9>] EFLAGS: 00010246 CPU: 0
   ...: [17234.280005] EIP is at 0xe0ea32e9
   ...: [17234.280005] EAX: bffffdf4 EBX: b7fd7ff4 ECX: 261e90fa EDX:
   00000001
   ...: [17234.280005] ESI: 00000000 EDI: 00000000 EBP: bffffdc8 ESP:
   dfa55fe4
   ...: [17234.280005]  DS: 007b ES: 007b FS: 0000 GS: 00e0 SS: 0068
   ...: [17234.280005]  08048396 00000073 00000246 bffffd4c 0000007b 00000000
   00000000
   ...: [17234.280005] ---[ end trace 323827b587f0e55d ]---

   And also this to dmesg:
   [17234.280005] BUG: unable to handle kernel paging request at e0ea32e9
   [17234.280005] IP: [<e0ea32e9>] 0xe0ea32e9
   [17234.280005] *pde = 1d9dc067 *pte = 00000000
   [17234.280005] Oops: 0000 [#2] SMP
   [17234.280005] last sysfs file: /sys/devices/virtual/net/lo/operstate
   [17234.280005] Modules linked in: yarr loop snd_ens1371 gameport
   snd_rawmidi snd_seq_device snd_ac97_codec ac97_bus snd_pcm snd_timer snd
   i2c_piix4 soundcore shpchp snd_page_alloc pci_hotplug i2c_core parport_pc
   psmouse parport pcspkr serio_raw evdev container processor ac button ext3
   jbd mbcache sg sd_mod crc_t10dif sr_mod cdrom uhci_hcd ata_generic mptspi
   mptscsih ata_piix ehci_hcd mptbase libata thermal floppy pcnet32 mii
   usbcore nls_base scsi_transport_spi scsi_mod thermal_sys [last unloaded:
   yarr]
   [17234.280005]
   [17234.280005] Pid: 1772, comm: intr_poc Tainted: G      D W 
   (2.6.32-5-686 #1) VMware Virtual Platform
   [17234.280005] EIP: 0060:[<e0ea32e9>] EFLAGS: 00010246 CPU: 0
   [17234.280005] EIP is at 0xe0ea32e9
   [17234.280005] EAX: bffffdf4 EBX: b7fd7ff4 ECX: 261e90fa EDX: 00000001
   [17234.280005] ESI: 00000000 EDI: 00000000 EBP: bffffdc8 ESP: dfa55fe4
   [17234.280005]  DS: 007b ES: 007b FS: 0000 GS: 00e0 SS: 0068
   [17234.280005] Process intr_poc (pid: 1772, ti=dfa54000 task=df818000
   task.ti=dfa54000)
   [17234.280005] Stack:
   [17234.280005]  08048396 00000073 00000246 bffffd4c 0000007b 00000000
   00000000
   [17234.280005] Call Trace:
   [17234.280005] Code:  Bad EIP value.
   [17234.280005] EIP: [<e0ea32e9>] 0xe0ea32e9 SS:ESP 0068:dfa55fe4
   [17234.280005] CR2: 00000000e0ea32e9
   [17234.280005] ---[ end trace 323827b587f0e55d ]---

   I have written with bold font those things that makes me think.

   Yarr is the name of my module and intr_poc the program that makes int
   $<n>. When I check the IDT to look the address of the interrupt handler I
   have installed I obtain the address of the function that I want to be my
   interrupt handler. I checked it against /proc/kallsyms, where the symbols
   of my module are. This function is just this:

   static irqreturn_t yarrIntrDesc(int irq, void *dev_id) {
       printk("YARR! WE ARE MIGHTY PIRATES!\n");
       return IRQ_RETVAL(0);
   }

   And the symbols of my module are these:

   $ egrep "yarr" /proc/kallsyms
   e0eae2e9 t yarrIntrDesc [yarr]
   ...

   We can observe that the EIP is near this function (it fails not at the
   beginning but in the middle of the function, so it enters here...).

   We can see in dmesg's message that "Bad EIP value", and also a line
   talking about pde and pte. PTE is the Page Table Entry and PDE in fact a
   pmd_t structure which takes part of the kernel when we have more than 2
   levels of page indexing.

   I'm thinking about page permissions since there are references to PTE
   (with an impressive value of 0). Another thing that makes me look at it is
   the distance between my interrupt handler (e0eae2e9) and EIP when the
   error issues (e0ea32e9). They difference is exactly 45056 bytes 0xb000
   bytes... this number is too precise to be random xD.

   What the heck is going on here? Anyone has an idea?

   Thanks in advance.

   --
   Ole


----- End forwarded message -----

-- 
-bill!
Sent from my computer


More information about the vox-tech mailing list