Re: Re: Low Level Interrupt Handling

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



  
>> Taking an example of IRQ 3, if 00001011 (0x0B) is the actual bit 
>> string CPU receives for IRQ 3, then how does CPU comes to know the >> actual IRQ number like 3, in kernel I did not see any code which 
>> interprets the received bit string to actual IRQ number. Where this >> conversion is done ?

>> Please if you know some link to good article which can tell how CPU >> interprets the IRQ number received from PIC and map it to the IDT 
>> entry inde

Hi Gaurav,

Please go thro the notes below - might be an interesting read for you.

Hardware interrupt processing..........(in 2.4.X only)

The IDT is the OS's view of hardware interrupts, which seem to have their own numbering scheme, based on the physical irq line with which each one is associated.

1)  Table of 1st-level handlers for each irq.

arch/i386/kernel/i8259.c

void (*interrupt[NR_IRQS])(void) = {
        IRQLIST_16(0x0),

#ifdef CONFIG_X86_IO_APIC
                         IRQLIST_16(0x1), IRQLIST_16(0x2), IRQLIST_16(0x3),
        IRQLIST_16(0x4), IRQLIST_16(0x5), IRQLIST_16(0x6), IRQLIST_16(0x7),
        IRQLIST_16(0x8), IRQLIST_16(0x9), IRQLIST_16(0xa), IRQLIST_16(0xb),
        IRQLIST_16(0xc), IRQLIST_16(0xd)
#endif
}

For a standard PC, there are 16 entries for this interrupt[] table. The generating macro IRQLIST_16() sets up these 16 entries

The #ifdef implies many more hardware interrupt lines so further 208 entries setup.


2) To generate the names/entries in the interrupt[] table:

arch/i386/kernel/i8259.c

#define IRQ(x,y) \
        IRQ##x##y##_interrupt

#define IRQLIST_16(x) \
        IRQ(x,0), IRQ(x,1), IRQ(x,2), IRQ(x,3), \
        IRQ(x,4), IRQ(x,5), IRQ(x,6), IRQ(x,7), \
        IRQ(x,8), IRQ(x,9), IRQ(x,a), IRQ(x,b), \
        IRQ(x,c), IRQ(x,d), IRQ(x,e), IRQ(x,f)

Ex: if passed(0,2) as params, then IRQ02_interrupt is the entry!

3)  Generating of the first level interrupt handlers

In step 2, the array of pointers to 1st level of handlers was initialized. The handlers are build using 
some really ugh! (read ugly) macros, which create low-level assembly routines that save register-context
and call 2nd level handler, do_IRQ() which does all further operations.


arch/i386/kernel/i8259..c

==> code for building handler stubs for hardware interrupts

/*
 * Common place to define all x86 IRQ vectors
 *
 * This builds up the IRQ handler stubs using some ugly macros in irq.h
 *
 * These macros create the low-level assembly IRQ routines that save
 * register context and call do_IRQ(). do_IRQ() then does all the
 * operations that are needed to keep the AT (or SMP IOAPIC)
 * interrupt-controller happy.
 */

BUILD_COMMON_IRQ()

#define BI(x,y) \
        BUILD_IRQ(x##y)

#define BUILD_16_IRQS(x) \
        BI(x,0) BI(x,1) BI(x,2) BI(x,3) \
        BI(x,4) BI(x,5) BI(x,6) BI(x,7) \
        BI(x,8) BI(x,9) BI(x,a) BI(x,b) \
        BI(x,c) BI(x,d) BI(x,e) BI(x,f)

/*
 * ISA PIC or low IO-APIC triggered (INTA-cycle or APIC) interrupts:
 * (these are usually mapped to vectors 0x20-0x2f)
 */
BUILD_16_IRQS(0x0)

#ifdef CONFIG_X86_IO_APIC
/*
 * The IO-APIC gives us many more interrupt sources. Most of these
 * are unused but an SMP system is supposed to have enough memory ...
 * sometimes (mostly wrt. hw bugs) we get corrupted vectors all
 * across the spectrum, so we really want to be prepared to get all
 * of these. Plus, more powerful systems might have more than 64
 * IO-APIC registers.
 *
 * (these are usually mapped into the 0x30-0xff vector range)
 */
                   BUILD_16_IRQS(0x1) BUILD_16_IRQS(0x2) BUILD_16_IRQS(0x3)
BUILD_16_IRQS(0x4) BUILD_16_IRQS(0x5) BUILD_16_IRQS(0x6) BUILD_16_IRQS(0x7)
BUILD_16_IRQS(0x8) BUILD_16_IRQS(0x9) BUILD_16_IRQS(0xa) BUILD_16_IRQS(0xb)
BUILD_16_IRQS(0xc) BUILD_16_IRQS(0xd)
#endif

#undef BUILD_16_IRQS
#undef BI


So, BUILD_16_IRQS(0x0) actually instantiates first 16 stubs to handle interrupts from PC hardware.
So, it evaluates to BUILD_IRQ(00) to BUILD_IRQ(0f)


At the bottom level, actual interrupt handlers are generated using macro from <asm-i386/hw_irq.h>

#define BUILD_COMMON_IRQ() \
asmlinkage void call_do_IRQ(void); \
__asm__( \
        "\n" __ALIGN_STR"\n" \
        "common_interrupt:\n\t" \
        SAVE_ALL \
        SYMBOL_NAME_STR(call_do_IRQ)":\n\t" \
        "call " SYMBOL_NAME_STR(do_IRQ) "\n\t" \
       "jmp ret_from_intr\n");

The macro saves registers on stack and calles do_IRQ() and then takes ret_from_intr exit path.


The above is called by all the stubs. To generate each of these stubs.......
<asm-i386/hw_irq.h>

#define BUILD_IRQ(nr) \
asmlinkage void IRQ_NAME(nr); \
__asm__( \
"\n"__ALIGN_STR"\n" \
SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
        "pushl $"#nr"-256\n\t" \
        "jmp common_interrupt");

jmp common_interrupt will jump into the target lable in BUILD_COMMON_IRQ....all handler stubs jump there.


So, lets say parameter 6 was passed into BUILD_IRQ() macro. Then irq6 is setup eventually and entry in IDt points to IRQ6_interrupt: label. The handler then jumps to common_interrupt: where all hardware 
registers are saved. Finally, control transfers to the do_IRQ() which is 2nd level handler and there on.
When it returns, it jumps to ret_from_interrupt.


That's the first level handler processing in 2.4

Hope this helps,

Thanks,
Vinod
















On Thu, 16 Sep 2004 Clemens Buchacher wrote :
>I removed these from my group reply, as they don't seem to partake in
>this discussion.
>
>Cc: rubini@xxxxxxxx, rubini@xxxxxxxxx, rubini@xxxxxxxx,
>         rubini@xxxxxxxxxxxxx, rubini@xxxxxxx
>
>On Wed, Sep 15, 2004 at 12:00:24AM +0530, Dhiman, Gaurav wrote:
> > [..] If this is the physical base address of IDT, where in kernel are
> > we setting the "idtr" register, so CPU has reference to IDT.
>
>It's set in head.S. Search for idt_descr. And it's the virtual address.
>The physical address would be (virt_addr - KERNEL_OFFSET).
>
> > [...] But according to my knowledge and what I read IDT should not
> > exceed more than 1 MB.
>
>That limitation applies to the real mode. In protected mode, the IDTR
>provides not only a base address, but also a limit (which _can_ exceed 1
>MB).
>
> > d) As Intel CPU multiplies the IRQ number (which it receives from PIC)
> > with 4 (as entry in IDT should be of 4 bytes), why linux IDT entries are
> > of 16 bytes. Don't they corrupt the CPU calculations for getting the
> > actual ISR address form IDT entry ?
>
>4 bytes in real mode, in protected mode 8 bytes for ia32, 16 bytes for
>ia64.
>
> > [...] in kernel I did not see any code which interprets the received
> > bit string to actual IRQ number. Where this conversion is done ?
>
>2.4: include/asm-i386/hw_irq.h:BUILD_IRQ(nr)
>2.6: entry.S:irq_entries_start
>
>For each vector the vector number (minus 256) is pushed on the stack and
>retrieved in do_IRQ (regs.orig_eax) to determine the IRQ number.
>
> > Please if you know some link to good article which can tell how CPU
> > interprets the IRQ number received from PIC and map it to the IDT entry
> > index.
>
>Intel Architecture Manuals.
>
>--
>Kernelnewbies: Help each other learn about the Linux kernel.
>Archive:       http://mail.nl.linux.org/kernelnewbies/
>FAQ:           http://kernelnewbies.org/faq/
>

[Index of Archives]     [Newbies FAQ]     [Linux Kernel Mentors]     [Linux Kernel Development]     [IETF Annouce]     [Git]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux SCSI]     [Linux ACPI]
  Powered by Linux