x86/idt: Prepare for table based init
authorThomas Gleixner <tglx@linutronix.de>
Mon, 28 Aug 2017 06:47:49 +0000 (08:47 +0200)
committerIngo Molnar <mingo@kernel.org>
Tue, 29 Aug 2017 10:07:27 +0000 (12:07 +0200)
The IDT setup code is handled in several places. All of them use variants
of set_intr_gate() inlines. This can be done with a table based
initialization, which allows to reduce the inline zoo and puts all IDT
related code and information into a single place.

Add the infrastructure.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Andy Lutomirski <luto@kernel.org>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
Link: http://lkml.kernel.org/r/20170828064958.849877032@linutronix.de
Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/kernel/idt.c

index 70ca24853ef073f2c0e99a29747a5857d638d83b..ae6fc12fd64f044687a59f80b1eb393e04d5b710 100644 (file)
@@ -5,8 +5,49 @@
  */
 #include <linux/interrupt.h>
 
+#include <asm/traps.h>
+#include <asm/proto.h>
 #include <asm/desc.h>
 
+struct idt_data {
+       unsigned int    vector;
+       unsigned int    segment;
+       struct idt_bits bits;
+       const void      *addr;
+};
+
+#define DPL0           0x0
+#define DPL3           0x3
+
+#define DEFAULT_STACK  0
+
+#define G(_vector, _addr, _ist, _type, _dpl, _segment) \
+       {                                               \
+               .vector         = _vector,              \
+               .bits.ist       = _ist,                 \
+               .bits.type      = _type,                \
+               .bits.dpl       = _dpl,                 \
+               .bits.p         = 1,                    \
+               .addr           = _addr,                \
+               .segment        = _segment,             \
+       }
+
+/* Interrupt gate */
+#define INTG(_vector, _addr)                           \
+       G(_vector, _addr, DEFAULT_STACK, GATE_INTERRUPT, DPL0, __KERNEL_CS)
+
+/* System interrupt gate */
+#define SYSG(_vector, _addr)                           \
+       G(_vector, _addr, DEFAULT_STACK, GATE_INTERRUPT, DPL3, __KERNEL_CS)
+
+/* Interrupt gate with interrupt stack */
+#define ISTG(_vector, _addr, _ist)                     \
+       G(_vector, _addr, _ist, GATE_INTERRUPT, DPL0, __KERNEL_CS)
+
+/* Task gate */
+#define TSKG(_vector, _gdt)                            \
+       G(_vector, NULL, DEFAULT_STACK, GATE_TASK, DPL0, _gdt << 3)
+
 /* Must be page-aligned because the real IDT is used in a fixmap. */
 gate_desc idt_table[IDT_ENTRIES] __page_aligned_bss;
 
@@ -25,6 +66,32 @@ const struct desc_ptr debug_idt_descr = {
 };
 #endif
 
+static inline void idt_init_desc(gate_desc *gate, const struct idt_data *d)
+{
+       unsigned long addr = (unsigned long) d->addr;
+
+       gate->offset_low        = (u16) addr;
+       gate->segment           = (u16) d->segment;
+       gate->bits              = d->bits;
+       gate->offset_middle     = (u16) (addr >> 16);
+#ifdef CONFIG_X86_64
+       gate->offset_high       = (u32) (addr >> 32);
+       gate->reserved          = 0;
+#endif
+}
+
+static __init void
+idt_setup_from_table(gate_desc *idt, const struct idt_data *t, int size)
+{
+       gate_desc desc;
+
+       for (; size > 0; t++, size--) {
+               idt_init_desc(&desc, t);
+               set_bit(t->vector, used_vectors);
+               write_idt_entry(idt, t->vector, &desc);
+       }
+}
+
 /**
  * idt_setup_early_handler - Initializes the idt table with early handlers
  */