x86 build IDT entry stubs

.section .init.rodata,"a"
ENTRY(interrupt)
.section .entry.text
.p2align 5
.p2align CONFIG_X86_L1_CACHE_SHIFT
ENTRY(irq_entries_start)
INTR_FRAME
vector=FIRST_EXTERNAL_VECTOR
.rept (NR_VECTORS-FIRST_EXTERNAL_VECTOR+6)/7
.balign 32
  .rept 7
    .if vector < NR_VECTORS
      .if vector <> FIRST_EXTERNAL_VECTOR
CFI_ADJUST_CFA_OFFSET -8
      .endif
1: pushq_cfi $(~vector+0x80) /* Note: always in signed byte range */
      .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6
jmp 2f
      .endif
      .previous
.quad 1b
      .section .entry.text
vector=vector+1
    .endif
  .endr
2: jmp common_interrupt
.endr
CFI_ENDPROC
END(irq_entries_start)


.previous
END(interrupt)

.previous


This can  be really confusing at first glance.

It does the following:

1. adding an entry (interrupt) in rodata section
2. break the vector range into a number of 7 stubs pieces so that each one of them can be packed into a single cache line
3. for each stub snippet, 7 entries are installed

crash> x/20gi irq_entries_start

    0xffffffff81770900 <irq_entries_start>:      pushq  $0x5f

    0xffffffff81770902 <irq_entries_start+2>:    jmp    0xffffffff8177091a <irq_entries_start+26>

    0xffffffff81770904 <irq_entries_start+4>:    pushq  $0x5e

    0xffffffff81770906 <irq_entries_start+6>:    jmp    0xffffffff8177091a <irq_entries_start+26>

    0xffffffff81770908 <irq_entries_start+8>:    pushq  $0x5d

    0xffffffff8177090a <irq_entries_start+10>:   jmp    0xffffffff8177091a <irq_entries_start+26>

    0xffffffff8177090c <irq_entries_start+12>:   pushq  $0x5c

    0xffffffff8177090e <irq_entries_start+14>:   jmp    0xffffffff8177091a <irq_entries_start+26>

    0xffffffff81770910 <irq_entries_start+16>:   pushq  $0x5b

    0xffffffff81770912 <irq_entries_start+18>:   jmp    0xffffffff8177091a <irq_entries_start+26>

    0xffffffff81770914 <irq_entries_start+20>:   pushq  $0x5a

    0xffffffff81770916 <irq_entries_start+22>:   jmp    0xffffffff8177091a <irq_entries_start+26>

    0xffffffff81770918 <irq_entries_start+24>:   pushq  $0x59

    0xffffffff8177091a <irq_entries_start+26>:   jmpq   0xffffffff81767500 <common_interrupt>

    0xffffffff8177091f <irq_entries_start+31>:   nop

last entry directly jump to common_interrupt. the others would cause a double jump which could have a negative effect on some pipelines.

jmpq to common_interrupt cost 5 bytes. the other short jump costs 2 bytes


4. each time a stub is installed, a 64bits space is allocated in rodata section. at the end, it forms the IDT table.

.previous

.quad 1b

at the end, it forms an array starting from symbol interrupt in rodata. 

according to native_init_IRQ,

 void __init native_init_IRQ(void)

 {

         int i;

   

         /* Execute any quirks before the call gates are initialised: */

         x86_init.irqs.pre_vector_init();

   

         apic_intr_init();

   

         /*

          * Cover the whole vector space, no vector can escape

          * us. (some of these will be overridden and become

          * 'special' SMP interrupts)

          */

         i = FIRST_EXTERNAL_VECTOR;

         for_each_clear_bit_from(i, used_vectors, NR_VECTORS) {

                 /* IA32_SYSCALL_VECTOR could be used in trap_init already. */

                 set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]);

         }   

   

         if (!acpi_ioapic && !of_ioapic)

                 setup_irq(2, &irq2);

   

 #ifdef CONFIG_X86_32

         irq_ctx_init(smp_processor_id());

 #endif

 }

this is the actual IDT table.


Still cannot explain why it negates vector number and adding 0x80 - pushq_cfi $(~vector+0x80) 

0x80 will be subtracted right at the start of common_interrupt. And do_IRQ will negate it back. 

__visible unsigned int __irq_entry do_IRQ(struct pt_regs *regs)
{
        struct pt_regs *old_regs = set_irq_regs(regs);

        /* high bit used in ret_from_ code  */
        unsigned vector = ~regs->orig_ax;

we are still investigating ret_from_* to find some clue .....

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值