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
4. each time a stub is installed, a 64bits space is allocated in rodata section. at the end, it forms the IDT table.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
.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 .....