aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDenys Vlasenko <dvlasenk@redhat.com>2015-04-03 15:49:13 -0400
committerIngo Molnar <mingo@kernel.org>2015-04-08 03:02:13 -0400
commit3304c9c37bef30ebd2ef71d986e6568372ce80f8 (patch)
treebac6895e23c14ddb5cad6c322ab9286cc320d899
parentfffbb5dcfd29f8831e41b4dd2ab938bd36d35283 (diff)
x86/asm/entry/irq: Simplify interrupt dispatch table (IDT) layout
Interrupt entry points are handled with the following code, each 32-byte code block contains seven entry points: ... [push][jump 22] // 4 bytes [push][jump 18] // 4 bytes [push][jump 14] // 4 bytes [push][jump 10] // 4 bytes [push][jump 6] // 4 bytes [push][jump 2] // 4 bytes [push][jump common_interrupt][padding] // 8 bytes [push][jump] [push][jump] [push][jump] [push][jump] [push][jump] [push][jump] [push][jump common_interrupt][padding] [padding_2] common_interrupt: And there is a table which holds pointers to every entry point, IOW: to every push. In cold cache, two jumps are still costlier than one, even though we get the benefit of them residing in the same cacheline. This change replaces short jumps with near ones to 'common_interrupt', and pads every push+jump pair to 8 bytes. This way, each interrupt takes only one jump. This change replaces ".p2align CONFIG_X86_L1_CACHE_SHIFT" before dispatch table with ".align 8" - we do not need anything stronger than that. The table of entry addresses (the interrupt[] array) is no longer necessary, the address of entries can be easily calculated as (irq_entries_start + i*8). text data bss dec hex filename 12546 0 0 12546 3102 entry_64.o.before 11626 0 0 11626 2d6a entry_64.o The size decrease is because 1656 bytes of .init.rodata are gone. That's initdata, though. The resident size does go up a bit. Run-tested (32 and 64 bits). Acked-and-Tested-by: Borislav Petkov <bp@suse.de> Signed-off-by: Denys Vlasenko <dvlasenk@redhat.com> Cc: Alexei Starovoitov <ast@plumgrid.com> Cc: Andy Lutomirski <luto@amacapital.net> Cc: Borislav Petkov <bp@alien8.de> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Kees Cook <keescook@chromium.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Oleg Nesterov <oleg@redhat.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Will Drewry <wad@chromium.org> Link: http://lkml.kernel.org/r/1428090553-7283-1-git-send-email-dvlasenk@redhat.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--arch/x86/include/asm/hw_irq.h5
-rw-r--r--arch/x86/kernel/entry_32.S41
-rw-r--r--arch/x86/kernel/entry_64.S41
-rw-r--r--arch/x86/kernel/irqinit.c3
-rw-r--r--arch/x86/lguest/boot.c3
5 files changed, 26 insertions, 67 deletions
diff --git a/arch/x86/include/asm/hw_irq.h b/arch/x86/include/asm/hw_irq.h
index 9662290e0b20..e9571ddabc4f 100644
--- a/arch/x86/include/asm/hw_irq.h
+++ b/arch/x86/include/asm/hw_irq.h
@@ -181,10 +181,9 @@ extern __visible void smp_call_function_single_interrupt(struct pt_regs *);
181extern __visible void smp_invalidate_interrupt(struct pt_regs *); 181extern __visible void smp_invalidate_interrupt(struct pt_regs *);
182#endif 182#endif
183 183
184extern void (*__initconst interrupt[FIRST_SYSTEM_VECTOR 184extern char irq_entries_start[];
185 - FIRST_EXTERNAL_VECTOR])(void);
186#ifdef CONFIG_TRACING 185#ifdef CONFIG_TRACING
187#define trace_interrupt interrupt 186#define trace_irq_entries_start irq_entries_start
188#endif 187#endif
189 188
190#define VECTOR_UNDEFINED (-1) 189#define VECTOR_UNDEFINED (-1)
diff --git a/arch/x86/kernel/entry_32.S b/arch/x86/kernel/entry_32.S
index effa2793feba..02bec0f1d1e1 100644
--- a/arch/x86/kernel/entry_32.S
+++ b/arch/x86/kernel/entry_32.S
@@ -723,43 +723,22 @@ END(sysenter_badsys)
723.endm 723.endm
724 724
725/* 725/*
726 * Build the entry stubs and pointer table with some assembler magic. 726 * Build the entry stubs with some assembler magic.
727 * We pack 7 stubs into a single 32-byte chunk, which will fit in a 727 * We pack 1 stub into every 8-byte block.
728 * single cache line on all modern x86 implementations.
729 */ 728 */
730.section .init.rodata,"a" 729 .align 8
731ENTRY(interrupt)
732.section .entry.text, "ax"
733 .p2align 5
734 .p2align CONFIG_X86_L1_CACHE_SHIFT
735ENTRY(irq_entries_start) 730ENTRY(irq_entries_start)
736 RING0_INT_FRAME 731 RING0_INT_FRAME
737vector=FIRST_EXTERNAL_VECTOR 732 vector=FIRST_EXTERNAL_VECTOR
738.rept (FIRST_SYSTEM_VECTOR-FIRST_EXTERNAL_VECTOR+6)/7 733 .rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
739 .balign 32 734 pushl_cfi $(~vector+0x80) /* Note: always in signed byte range */
740 .rept 7 735 vector=vector+1
741 .if vector < FIRST_SYSTEM_VECTOR 736 jmp common_interrupt
742 .if vector <> FIRST_EXTERNAL_VECTOR
743 CFI_ADJUST_CFA_OFFSET -4 737 CFI_ADJUST_CFA_OFFSET -4
744 .endif 738 .align 8
7451: pushl_cfi $(~vector+0x80) /* Note: always in signed byte range */ 739 .endr
746 .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6
747 jmp 2f
748 .endif
749 .previous
750 .long 1b
751 .section .entry.text, "ax"
752vector=vector+1
753 .endif
754 .endr
7552: jmp common_interrupt
756.endr
757END(irq_entries_start) 740END(irq_entries_start)
758 741
759.previous
760END(interrupt)
761.previous
762
763/* 742/*
764 * the CPU automatically disables interrupts when executing an IRQ vector, 743 * the CPU automatically disables interrupts when executing an IRQ vector,
765 * so IRQ-flags tracing has to follow that: 744 * so IRQ-flags tracing has to follow that:
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index e4c810395bae..4ca03c518ab4 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -608,44 +608,23 @@ ENTRY(ret_from_fork)
608END(ret_from_fork) 608END(ret_from_fork)
609 609
610/* 610/*
611 * Build the entry stubs and pointer table with some assembler magic. 611 * Build the entry stubs with some assembler magic.
612 * We pack 7 stubs into a single 32-byte chunk, which will fit in a 612 * We pack 1 stub into every 8-byte block.
613 * single cache line on all modern x86 implementations.
614 */ 613 */
615 .section .init.rodata,"a" 614 .align 8
616ENTRY(interrupt)
617 .section .entry.text
618 .p2align 5
619 .p2align CONFIG_X86_L1_CACHE_SHIFT
620ENTRY(irq_entries_start) 615ENTRY(irq_entries_start)
621 INTR_FRAME 616 INTR_FRAME
622vector=FIRST_EXTERNAL_VECTOR 617 vector=FIRST_EXTERNAL_VECTOR
623.rept (FIRST_SYSTEM_VECTOR-FIRST_EXTERNAL_VECTOR+6)/7 618 .rept (FIRST_SYSTEM_VECTOR - FIRST_EXTERNAL_VECTOR)
624 .balign 32 619 pushq_cfi $(~vector+0x80) /* Note: always in signed byte range */
625 .rept 7 620 vector=vector+1
626 .if vector < FIRST_SYSTEM_VECTOR 621 jmp common_interrupt
627 .if vector <> FIRST_EXTERNAL_VECTOR
628 CFI_ADJUST_CFA_OFFSET -8 622 CFI_ADJUST_CFA_OFFSET -8
629 .endif 623 .align 8
6301: pushq_cfi $(~vector+0x80) /* Note: always in signed byte range */ 624 .endr
631 .if ((vector-FIRST_EXTERNAL_VECTOR)%7) <> 6
632 jmp 2f
633 .endif
634 .previous
635 .quad 1b
636 .section .entry.text
637vector=vector+1
638 .endif
639 .endr
6402: jmp common_interrupt
641.endr
642 CFI_ENDPROC 625 CFI_ENDPROC
643END(irq_entries_start) 626END(irq_entries_start)
644 627
645.previous
646END(interrupt)
647.previous
648
649/* 628/*
650 * Interrupt entry/exit. 629 * Interrupt entry/exit.
651 * 630 *
diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c
index 70e181ea1eac..cd10a6437264 100644
--- a/arch/x86/kernel/irqinit.c
+++ b/arch/x86/kernel/irqinit.c
@@ -178,7 +178,8 @@ void __init native_init_IRQ(void)
178#endif 178#endif
179 for_each_clear_bit_from(i, used_vectors, first_system_vector) { 179 for_each_clear_bit_from(i, used_vectors, first_system_vector) {
180 /* IA32_SYSCALL_VECTOR could be used in trap_init already. */ 180 /* IA32_SYSCALL_VECTOR could be used in trap_init already. */
181 set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]); 181 set_intr_gate(i, irq_entries_start +
182 8 * (i - FIRST_EXTERNAL_VECTOR));
182 } 183 }
183#ifdef CONFIG_X86_LOCAL_APIC 184#ifdef CONFIG_X86_LOCAL_APIC
184 for_each_clear_bit_from(i, used_vectors, NR_VECTORS) 185 for_each_clear_bit_from(i, used_vectors, NR_VECTORS)
diff --git a/arch/x86/lguest/boot.c b/arch/x86/lguest/boot.c
index 8561585ee2c6..717908b16037 100644
--- a/arch/x86/lguest/boot.c
+++ b/arch/x86/lguest/boot.c
@@ -868,7 +868,8 @@ static void __init lguest_init_IRQ(void)
868 /* Some systems map "vectors" to interrupts weirdly. Not us! */ 868 /* Some systems map "vectors" to interrupts weirdly. Not us! */
869 __this_cpu_write(vector_irq[i], i - FIRST_EXTERNAL_VECTOR); 869 __this_cpu_write(vector_irq[i], i - FIRST_EXTERNAL_VECTOR);
870 if (i != SYSCALL_VECTOR) 870 if (i != SYSCALL_VECTOR)
871 set_intr_gate(i, interrupt[i - FIRST_EXTERNAL_VECTOR]); 871 set_intr_gate(i, irq_entries_start +
872 8 * (i - FIRST_EXTERNAL_VECTOR));
872 } 873 }
873 874
874 /* 875 /*