Clean up x86 interrupt entry code
PATCH 1/1 Clean up x86 interrupt entry code
This patch moves the generation of the asm interrupt entry stubs from i8259.c to entry.S. This allows it to be done with less code and without needing duplicate definitions of SAVE_ALL, GET_CURRENT, etc.
Signature · 1 line
Brian Gerst
arch/i386/kernel/entry.S +69 -7
@@ -47,6 +47,7 @@ #include <asm/errno.h> #include <asm/segment.h> #include <asm/smp.h> +#include <asm/irq_vectors.h> EBX = 0x00 ECX = 0x04
@@ -94,12 +95,12 @@ #ifdef CONFIG_PREEMPT #define preempt_stop cli -#define init_ret_intr \ - cli; \ - decl TI_PRE_COUNT(%ebx); +#define INC_PRE_COUNT(reg) incl TI_PRE_COUNT(reg); +#define DEC_PRE_COUNT(reg) decl TI_PRE_COUNT(reg); #else #define preempt_stop -#define init_ret_intr +#define INC_PRE_COUNT(reg) +#define DEC_PRE_COUNT(reg) #define resume_kernel restore_all #endif
@@ -210,9 +211,9 @@ # userspace resumption stub bypassing syscall exit tracing ALIGN -ENTRY(ret_from_intr) - GET_THREAD_INFO(%ebx) - init_ret_intr +ret_from_intr: + preempt_stop + DEC_PRE_COUNT(%ebx) ret_from_exception: movl EFLAGS(%esp), %eax # mix EFLAGS and CS movb CS(%esp), %al
@@ -335,6 +336,67 @@ movl $-ENOSYS,EAX(%esp) jmp resume_userspace +/* + * Build the entry stubs and pointer table with + * some assembler magic. + */ +.data +ENTRY(interrupt) +.text + +vector=0 +ENTRY(irq_entries_start) +.rept NR_IRQS + ALIGN +1: pushl $vector-256 + jmp common_interrupt +.data + .long 1b +.text +vector=vector+1 +.endr + + ALIGN +common_interrupt: + SAVE_ALL + GET_THREAD_INFO(%ebx) + INC_PRE_COUNT(%ebx) + call SYMBOL_NAME(do_IRQ) + jmp ret_from_intr + +#define BUILD_INTERRUPT(name, nr) \ +ENTRY(name) \ + pushl $nr-256; \ + SAVE_ALL \ + GET_THREAD_INFO(%ebx); \ + INC_PRE_COUNT(%ebx) \ + call SYMBOL_NAME(smp_/**/name); \ + jmp ret_from_intr; + +/* + * The following vectors are part of the Linux architecture, there + * is no hardware IRQ pin equivalent for them, they are triggered + * through the ICC by us (IPIs) + */ +#ifdef CONFIG_SMP +BUILD_INTERRUPT(reschedule_interrupt,RESCHEDULE_VECTOR) +BUILD_INTERRUPT(invalidate_interrupt,INVALIDATE_TLB_VECTOR) +BUILD_INTERRUPT(call_function_interrupt,CALL_FUNCTION_VECTOR) +#endif + +/* + * every pentium local APIC has two 'local interrupts', with a + * soft-definable vector attached to both interrupts, one of + * which is a timer interrupt, the other one is error counter + * overflow. Linux uses the local APIC timer interrupt to get + * a much simpler SMP time architecture: + */ +#ifdef CONFIG_X86_LOCAL_APIC +BUILD_INTERRUPT(apic_timer_interrupt,LOCAL_TIMER_VECTOR) +BUILD_INTERRUPT(error_interrupt,ERROR_APIC_VECTOR) +BUILD_INTERRUPT(spurious_interrupt,SPURIOUS_APIC_VECTOR) +#endif + ENTRY(divide_error) pushl $0 # no error code pushl $ SYMBOL_NAME(do_divide_error)
arch/i386/kernel/i8259.c +0 -96
102 lines not on this page · raw message
arch/i386/kernel/io_apic.c +0 -1
@@ -597,7 +597,6 @@return current_vector; } -extern void (*interrupt[NR_IRQS ])(void );static struct hw_interrupt_type ioapic_level_irq_type;static struct hw_interrupt_type ioapic_edge_irq_type;
include/asm-i386/hw_irq.h +16 -131
165 lines not on this page · raw message
include/asm-i386/irq.h +1 -17
@@ -12,23 +12,7 @@#include <linux/config.h> #include <linux/sched.h> - -#define TIMER_IRQ 0 - -/* -* 16 8259A IRQ's, 208 potential APIC interrupt sources. -* Right now the APIC is mostly only used for SMP. -* 256 vectors is an architectural limit. (we can have -* more than 256 devices theoretically, but they will -* have to use shared interrupts) -* Since vectors 0x00-0x1f are used/reserved for the CPU, -* the usable vector space is 0x20-0xff (224 vectors) -*/ -#ifdef CONFIG_X86_IO_APIC -#define NR_IRQS 224 -#else -#define NR_IRQS 16 -#endif +#include <asm/irq_vectors.h> static __inline__int irq_cannonicalize (int irq) {
include/asm-i386/irq_vectors.h +64 -0
64 lines not on this page · raw message
arch/i386/kernel/entry.S line 216
Quoted 6 lines · Brian Gerst
arch/i386/kernel/entry.S +3
-3-ENTRY(ret_from_intr) - GET_THREAD_INFO(%ebx) - init_ret_intr +ret_from_intr: + preempt_stop + DEC_PRE_COUNT(%ebx)
You removed GET_THREAD_INFO and there does not seem to be a replacement. Is there some assurance *thread_info is now pointed to by %ebx here?
Robert Love
Quoted 4 lines · Robert Love
You removed
GET_THREAD_INFOand there does not seem to be a replacement. Is there some assurance*thread_infois now pointed to by %ebx here?
It seems to be always loaded by the common interrupt code (and %ebx is a call-saved register, so calling the interrupt handlers and returning doesn't clobber it).
But testing it may be a good idea ;^p
Linus
Quoted 3 lines · Linus Torvalds
It seems to be always loaded by the common interrupt code (and %ebx is a call-saved register, so calling the interrupt handlers and returning doesn't clobber it).
True enough. I guess I should of done this from the beginning ...
Quoted 1 line
But testing it may be a good idea ;^p
Of course I will, but it is hard (and subject to Heisenberg principals) to test that we preempt whenever necessary. Only with the patch I sent you earlier am I seeing no missed preemptions ... now to work on the egregiously long-held locks.
Robert Love
Quoted 15 lines · Robert Love
arch/i386/kernel/entry.S line 216
Quoted 6 lines · Brian Gerst
arch/i386/kernel/entry.S +3
-3-ENTRY(ret_from_intr) - GET_THREAD_INFO(%ebx) - init_ret_intr +ret_from_intr: + preempt_stop + DEC_PRE_COUNT(%ebx)You removed
GET_THREAD_INFOand there does not seem to be a replacement. Is there some assurance*thread_infois now pointed to by %ebx here?
Quoted 2 lines
Robert Love
Yes. It is set before the INC_PRE_COUNT and since it is preserved by called functions it is still set when it gets to ret_from_intr.
Signature · 1 line
Brian Gerst