1d8ed9d48SThomas Gleixner /* 2d8ed9d48SThomas Gleixner * Interrupt descriptor table related code 3d8ed9d48SThomas Gleixner * 4d8ed9d48SThomas Gleixner * This file is licensed under the GPL V2 5d8ed9d48SThomas Gleixner */ 6d8ed9d48SThomas Gleixner #include <linux/interrupt.h> 7d8ed9d48SThomas Gleixner 8*3318e974SThomas Gleixner #include <asm/traps.h> 9*3318e974SThomas Gleixner #include <asm/proto.h> 10d8ed9d48SThomas Gleixner #include <asm/desc.h> 11d8ed9d48SThomas Gleixner 12*3318e974SThomas Gleixner struct idt_data { 13*3318e974SThomas Gleixner unsigned int vector; 14*3318e974SThomas Gleixner unsigned int segment; 15*3318e974SThomas Gleixner struct idt_bits bits; 16*3318e974SThomas Gleixner const void *addr; 17*3318e974SThomas Gleixner }; 18*3318e974SThomas Gleixner 19*3318e974SThomas Gleixner #define DPL0 0x0 20*3318e974SThomas Gleixner #define DPL3 0x3 21*3318e974SThomas Gleixner 22*3318e974SThomas Gleixner #define DEFAULT_STACK 0 23*3318e974SThomas Gleixner 24*3318e974SThomas Gleixner #define G(_vector, _addr, _ist, _type, _dpl, _segment) \ 25*3318e974SThomas Gleixner { \ 26*3318e974SThomas Gleixner .vector = _vector, \ 27*3318e974SThomas Gleixner .bits.ist = _ist, \ 28*3318e974SThomas Gleixner .bits.type = _type, \ 29*3318e974SThomas Gleixner .bits.dpl = _dpl, \ 30*3318e974SThomas Gleixner .bits.p = 1, \ 31*3318e974SThomas Gleixner .addr = _addr, \ 32*3318e974SThomas Gleixner .segment = _segment, \ 33*3318e974SThomas Gleixner } 34*3318e974SThomas Gleixner 35*3318e974SThomas Gleixner /* Interrupt gate */ 36*3318e974SThomas Gleixner #define INTG(_vector, _addr) \ 37*3318e974SThomas Gleixner G(_vector, _addr, DEFAULT_STACK, GATE_INTERRUPT, DPL0, __KERNEL_CS) 38*3318e974SThomas Gleixner 39*3318e974SThomas Gleixner /* System interrupt gate */ 40*3318e974SThomas Gleixner #define SYSG(_vector, _addr) \ 41*3318e974SThomas Gleixner G(_vector, _addr, DEFAULT_STACK, GATE_INTERRUPT, DPL3, __KERNEL_CS) 42*3318e974SThomas Gleixner 43*3318e974SThomas Gleixner /* Interrupt gate with interrupt stack */ 44*3318e974SThomas Gleixner #define ISTG(_vector, _addr, _ist) \ 45*3318e974SThomas Gleixner G(_vector, _addr, _ist, GATE_INTERRUPT, DPL0, __KERNEL_CS) 46*3318e974SThomas Gleixner 47*3318e974SThomas Gleixner /* Task gate */ 48*3318e974SThomas Gleixner #define TSKG(_vector, _gdt) \ 49*3318e974SThomas Gleixner G(_vector, NULL, DEFAULT_STACK, GATE_TASK, DPL0, _gdt << 3) 50*3318e974SThomas Gleixner 51d8ed9d48SThomas Gleixner /* Must be page-aligned because the real IDT is used in a fixmap. */ 52d8ed9d48SThomas Gleixner gate_desc idt_table[IDT_ENTRIES] __page_aligned_bss; 53d8ed9d48SThomas Gleixner 5416bc18d8SThomas Gleixner struct desc_ptr idt_descr __ro_after_init = { 5516bc18d8SThomas Gleixner .size = (IDT_ENTRIES * 2 * sizeof(unsigned long)) - 1, 5616bc18d8SThomas Gleixner .address = (unsigned long) idt_table, 5716bc18d8SThomas Gleixner }; 5816bc18d8SThomas Gleixner 59d8ed9d48SThomas Gleixner #ifdef CONFIG_X86_64 60d8ed9d48SThomas Gleixner /* No need to be aligned, but done to keep all IDTs defined the same way. */ 61d8ed9d48SThomas Gleixner gate_desc debug_idt_table[IDT_ENTRIES] __page_aligned_bss; 62d8ed9d48SThomas Gleixner 63d8ed9d48SThomas Gleixner const struct desc_ptr debug_idt_descr = { 64d8ed9d48SThomas Gleixner .size = IDT_ENTRIES * 16 - 1, 65d8ed9d48SThomas Gleixner .address = (unsigned long) debug_idt_table, 66d8ed9d48SThomas Gleixner }; 67d8ed9d48SThomas Gleixner #endif 68e802a51eSThomas Gleixner 69*3318e974SThomas Gleixner static inline void idt_init_desc(gate_desc *gate, const struct idt_data *d) 70*3318e974SThomas Gleixner { 71*3318e974SThomas Gleixner unsigned long addr = (unsigned long) d->addr; 72*3318e974SThomas Gleixner 73*3318e974SThomas Gleixner gate->offset_low = (u16) addr; 74*3318e974SThomas Gleixner gate->segment = (u16) d->segment; 75*3318e974SThomas Gleixner gate->bits = d->bits; 76*3318e974SThomas Gleixner gate->offset_middle = (u16) (addr >> 16); 77*3318e974SThomas Gleixner #ifdef CONFIG_X86_64 78*3318e974SThomas Gleixner gate->offset_high = (u32) (addr >> 32); 79*3318e974SThomas Gleixner gate->reserved = 0; 80*3318e974SThomas Gleixner #endif 81*3318e974SThomas Gleixner } 82*3318e974SThomas Gleixner 83*3318e974SThomas Gleixner static __init void 84*3318e974SThomas Gleixner idt_setup_from_table(gate_desc *idt, const struct idt_data *t, int size) 85*3318e974SThomas Gleixner { 86*3318e974SThomas Gleixner gate_desc desc; 87*3318e974SThomas Gleixner 88*3318e974SThomas Gleixner for (; size > 0; t++, size--) { 89*3318e974SThomas Gleixner idt_init_desc(&desc, t); 90*3318e974SThomas Gleixner set_bit(t->vector, used_vectors); 91*3318e974SThomas Gleixner write_idt_entry(idt, t->vector, &desc); 92*3318e974SThomas Gleixner } 93*3318e974SThomas Gleixner } 94*3318e974SThomas Gleixner 95e802a51eSThomas Gleixner /** 96588787fdSThomas Gleixner * idt_setup_early_handler - Initializes the idt table with early handlers 97588787fdSThomas Gleixner */ 98588787fdSThomas Gleixner void __init idt_setup_early_handler(void) 99588787fdSThomas Gleixner { 100588787fdSThomas Gleixner int i; 101588787fdSThomas Gleixner 102588787fdSThomas Gleixner for (i = 0; i < NUM_EXCEPTION_VECTORS; i++) 103588787fdSThomas Gleixner set_intr_gate(i, early_idt_handler_array[i]); 10487e81786SThomas Gleixner #ifdef CONFIG_X86_32 10587e81786SThomas Gleixner for ( ; i < NR_VECTORS; i++) 10687e81786SThomas Gleixner set_intr_gate(i, early_ignore_irq); 10787e81786SThomas Gleixner #endif 108588787fdSThomas Gleixner load_idt(&idt_descr); 109588787fdSThomas Gleixner } 110588787fdSThomas Gleixner 111588787fdSThomas Gleixner /** 112e802a51eSThomas Gleixner * idt_invalidate - Invalidate interrupt descriptor table 113e802a51eSThomas Gleixner * @addr: The virtual address of the 'invalid' IDT 114e802a51eSThomas Gleixner */ 115e802a51eSThomas Gleixner void idt_invalidate(void *addr) 116e802a51eSThomas Gleixner { 117e802a51eSThomas Gleixner struct desc_ptr idt = { .address = (unsigned long) addr, .size = 0 }; 118e802a51eSThomas Gleixner 119e802a51eSThomas Gleixner load_idt(&idt); 120e802a51eSThomas Gleixner } 121