~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/kernel/idt.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  * Interrupt descriptor table related code
  4  */
  5 #include <linux/interrupt.h>
  6 
  7 #include <asm/cpu_entry_area.h>
  8 #include <asm/set_memory.h>
  9 #include <asm/traps.h>
 10 #include <asm/proto.h>
 11 #include <asm/desc.h>
 12 #include <asm/hw_irq.h>
 13 #include <asm/ia32.h>
 14 #include <asm/idtentry.h>
 15 
 16 #define DPL0            0x0
 17 #define DPL3            0x3
 18 
 19 #define DEFAULT_STACK   0
 20 
 21 #define G(_vector, _addr, _ist, _type, _dpl, _segment)  \
 22         {                                               \
 23                 .vector         = _vector,              \
 24                 .bits.ist       = _ist,                 \
 25                 .bits.type      = _type,                \
 26                 .bits.dpl       = _dpl,                 \
 27                 .bits.p         = 1,                    \
 28                 .addr           = _addr,                \
 29                 .segment        = _segment,             \
 30         }
 31 
 32 /* Interrupt gate */
 33 #define INTG(_vector, _addr)                            \
 34         G(_vector, _addr, DEFAULT_STACK, GATE_INTERRUPT, DPL0, __KERNEL_CS)
 35 
 36 /* System interrupt gate */
 37 #define SYSG(_vector, _addr)                            \
 38         G(_vector, _addr, DEFAULT_STACK, GATE_INTERRUPT, DPL3, __KERNEL_CS)
 39 
 40 #ifdef CONFIG_X86_64
 41 /*
 42  * Interrupt gate with interrupt stack. The _ist index is the index in
 43  * the tss.ist[] array, but for the descriptor it needs to start at 1.
 44  */
 45 #define ISTG(_vector, _addr, _ist)                      \
 46         G(_vector, _addr, _ist + 1, GATE_INTERRUPT, DPL0, __KERNEL_CS)
 47 #else
 48 #define ISTG(_vector, _addr, _ist)      INTG(_vector, _addr)
 49 #endif
 50 
 51 /* Task gate */
 52 #define TSKG(_vector, _gdt)                             \
 53         G(_vector, NULL, DEFAULT_STACK, GATE_TASK, DPL0, _gdt << 3)
 54 
 55 #define IDT_TABLE_SIZE          (IDT_ENTRIES * sizeof(gate_desc))
 56 
 57 static bool idt_setup_done __initdata;
 58 
 59 /*
 60  * Early traps running on the DEFAULT_STACK because the other interrupt
 61  * stacks work only after cpu_init().
 62  */
 63 static const __initconst struct idt_data early_idts[] = {
 64         INTG(X86_TRAP_DB,               asm_exc_debug),
 65         SYSG(X86_TRAP_BP,               asm_exc_int3),
 66 
 67 #ifdef CONFIG_X86_32
 68         /*
 69          * Not possible on 64-bit. See idt_setup_early_pf() for details.
 70          */
 71         INTG(X86_TRAP_PF,               asm_exc_page_fault),
 72 #endif
 73 #ifdef CONFIG_INTEL_TDX_GUEST
 74         INTG(X86_TRAP_VE,               asm_exc_virtualization_exception),
 75 #endif
 76 };
 77 
 78 /*
 79  * The default IDT entries which are set up in trap_init() before
 80  * cpu_init() is invoked. Interrupt stacks cannot be used at that point and
 81  * the traps which use them are reinitialized with IST after cpu_init() has
 82  * set up TSS.
 83  */
 84 static const __initconst struct idt_data def_idts[] = {
 85         INTG(X86_TRAP_DE,               asm_exc_divide_error),
 86         ISTG(X86_TRAP_NMI,              asm_exc_nmi, IST_INDEX_NMI),
 87         INTG(X86_TRAP_BR,               asm_exc_bounds),
 88         INTG(X86_TRAP_UD,               asm_exc_invalid_op),
 89         INTG(X86_TRAP_NM,               asm_exc_device_not_available),
 90         INTG(X86_TRAP_OLD_MF,           asm_exc_coproc_segment_overrun),
 91         INTG(X86_TRAP_TS,               asm_exc_invalid_tss),
 92         INTG(X86_TRAP_NP,               asm_exc_segment_not_present),
 93         INTG(X86_TRAP_SS,               asm_exc_stack_segment),
 94         INTG(X86_TRAP_GP,               asm_exc_general_protection),
 95         INTG(X86_TRAP_SPURIOUS,         asm_exc_spurious_interrupt_bug),
 96         INTG(X86_TRAP_MF,               asm_exc_coprocessor_error),
 97         INTG(X86_TRAP_AC,               asm_exc_alignment_check),
 98         INTG(X86_TRAP_XF,               asm_exc_simd_coprocessor_error),
 99 
100 #ifdef CONFIG_X86_32
101         TSKG(X86_TRAP_DF,               GDT_ENTRY_DOUBLEFAULT_TSS),
102 #else
103         ISTG(X86_TRAP_DF,               asm_exc_double_fault, IST_INDEX_DF),
104 #endif
105         ISTG(X86_TRAP_DB,               asm_exc_debug, IST_INDEX_DB),
106 
107 #ifdef CONFIG_X86_MCE
108         ISTG(X86_TRAP_MC,               asm_exc_machine_check, IST_INDEX_MCE),
109 #endif
110 
111 #ifdef CONFIG_X86_CET
112         INTG(X86_TRAP_CP,               asm_exc_control_protection),
113 #endif
114 
115 #ifdef CONFIG_AMD_MEM_ENCRYPT
116         ISTG(X86_TRAP_VC,               asm_exc_vmm_communication, IST_INDEX_VC),
117 #endif
118 
119         SYSG(X86_TRAP_OF,               asm_exc_overflow),
120 };
121 
122 static const struct idt_data ia32_idt[] __initconst = {
123 #if defined(CONFIG_IA32_EMULATION)
124         SYSG(IA32_SYSCALL_VECTOR,       asm_int80_emulation),
125 #elif defined(CONFIG_X86_32)
126         SYSG(IA32_SYSCALL_VECTOR,       entry_INT80_32),
127 #endif
128 };
129 
130 /*
131  * The APIC and SMP idt entries
132  */
133 static const __initconst struct idt_data apic_idts[] = {
134 #ifdef CONFIG_SMP
135         INTG(RESCHEDULE_VECTOR,                 asm_sysvec_reschedule_ipi),
136         INTG(CALL_FUNCTION_VECTOR,              asm_sysvec_call_function),
137         INTG(CALL_FUNCTION_SINGLE_VECTOR,       asm_sysvec_call_function_single),
138         INTG(REBOOT_VECTOR,                     asm_sysvec_reboot),
139 #endif
140 
141 #ifdef CONFIG_X86_THERMAL_VECTOR
142         INTG(THERMAL_APIC_VECTOR,               asm_sysvec_thermal),
143 #endif
144 
145 #ifdef CONFIG_X86_MCE_THRESHOLD
146         INTG(THRESHOLD_APIC_VECTOR,             asm_sysvec_threshold),
147 #endif
148 
149 #ifdef CONFIG_X86_MCE_AMD
150         INTG(DEFERRED_ERROR_VECTOR,             asm_sysvec_deferred_error),
151 #endif
152 
153 #ifdef CONFIG_X86_LOCAL_APIC
154         INTG(LOCAL_TIMER_VECTOR,                asm_sysvec_apic_timer_interrupt),
155         INTG(X86_PLATFORM_IPI_VECTOR,           asm_sysvec_x86_platform_ipi),
156 # if IS_ENABLED(CONFIG_KVM)
157         INTG(POSTED_INTR_VECTOR,                asm_sysvec_kvm_posted_intr_ipi),
158         INTG(POSTED_INTR_WAKEUP_VECTOR,         asm_sysvec_kvm_posted_intr_wakeup_ipi),
159         INTG(POSTED_INTR_NESTED_VECTOR,         asm_sysvec_kvm_posted_intr_nested_ipi),
160 # endif
161 # ifdef CONFIG_IRQ_WORK
162         INTG(IRQ_WORK_VECTOR,                   asm_sysvec_irq_work),
163 # endif
164         INTG(SPURIOUS_APIC_VECTOR,              asm_sysvec_spurious_apic_interrupt),
165         INTG(ERROR_APIC_VECTOR,                 asm_sysvec_error_interrupt),
166 # ifdef CONFIG_X86_POSTED_MSI
167         INTG(POSTED_MSI_NOTIFICATION_VECTOR,    asm_sysvec_posted_msi_notification),
168 # endif
169 #endif
170 };
171 
172 /* Must be page-aligned because the real IDT is used in the cpu entry area */
173 static gate_desc idt_table[IDT_ENTRIES] __page_aligned_bss;
174 
175 static struct desc_ptr idt_descr __ro_after_init = {
176         .size           = IDT_TABLE_SIZE - 1,
177         .address        = (unsigned long) idt_table,
178 };
179 
180 void load_current_idt(void)
181 {
182         lockdep_assert_irqs_disabled();
183         load_idt(&idt_descr);
184 }
185 
186 #ifdef CONFIG_X86_F00F_BUG
187 bool idt_is_f00f_address(unsigned long address)
188 {
189         return ((address - idt_descr.address) >> 3) == 6;
190 }
191 #endif
192 
193 static __init void
194 idt_setup_from_table(gate_desc *idt, const struct idt_data *t, int size, bool sys)
195 {
196         gate_desc desc;
197 
198         for (; size > 0; t++, size--) {
199                 idt_init_desc(&desc, t);
200                 write_idt_entry(idt, t->vector, &desc);
201                 if (sys)
202                         set_bit(t->vector, system_vectors);
203         }
204 }
205 
206 static __init void set_intr_gate(unsigned int n, const void *addr)
207 {
208         struct idt_data data;
209 
210         init_idt_data(&data, n, addr);
211 
212         idt_setup_from_table(idt_table, &data, 1, false);
213 }
214 
215 /**
216  * idt_setup_early_traps - Initialize the idt table with early traps
217  *
218  * On X8664 these traps do not use interrupt stacks as they can't work
219  * before cpu_init() is invoked and sets up TSS. The IST variants are
220  * installed after that.
221  */
222 void __init idt_setup_early_traps(void)
223 {
224         idt_setup_from_table(idt_table, early_idts, ARRAY_SIZE(early_idts),
225                              true);
226         load_idt(&idt_descr);
227 }
228 
229 /**
230  * idt_setup_traps - Initialize the idt table with default traps
231  */
232 void __init idt_setup_traps(void)
233 {
234         idt_setup_from_table(idt_table, def_idts, ARRAY_SIZE(def_idts), true);
235 
236         if (ia32_enabled())
237                 idt_setup_from_table(idt_table, ia32_idt, ARRAY_SIZE(ia32_idt), true);
238 }
239 
240 #ifdef CONFIG_X86_64
241 /*
242  * Early traps running on the DEFAULT_STACK because the other interrupt
243  * stacks work only after cpu_init().
244  */
245 static const __initconst struct idt_data early_pf_idts[] = {
246         INTG(X86_TRAP_PF,               asm_exc_page_fault),
247 };
248 
249 /**
250  * idt_setup_early_pf - Initialize the idt table with early pagefault handler
251  *
252  * On X8664 this does not use interrupt stacks as they can't work before
253  * cpu_init() is invoked and sets up TSS. The IST variant is installed
254  * after that.
255  *
256  * Note, that X86_64 cannot install the real #PF handler in
257  * idt_setup_early_traps() because the memory initialization needs the #PF
258  * handler from the early_idt_handler_array to initialize the early page
259  * tables.
260  */
261 void __init idt_setup_early_pf(void)
262 {
263         idt_setup_from_table(idt_table, early_pf_idts,
264                              ARRAY_SIZE(early_pf_idts), true);
265 }
266 #endif
267 
268 static void __init idt_map_in_cea(void)
269 {
270         /*
271          * Set the IDT descriptor to a fixed read-only location in the cpu
272          * entry area, so that the "sidt" instruction will not leak the
273          * location of the kernel, and to defend the IDT against arbitrary
274          * memory write vulnerabilities.
275          */
276         cea_set_pte(CPU_ENTRY_AREA_RO_IDT_VADDR, __pa_symbol(idt_table),
277                     PAGE_KERNEL_RO);
278         idt_descr.address = CPU_ENTRY_AREA_RO_IDT;
279 }
280 
281 /**
282  * idt_setup_apic_and_irq_gates - Setup APIC/SMP and normal interrupt gates
283  */
284 void __init idt_setup_apic_and_irq_gates(void)
285 {
286         int i = FIRST_EXTERNAL_VECTOR;
287         void *entry;
288 
289         idt_setup_from_table(idt_table, apic_idts, ARRAY_SIZE(apic_idts), true);
290 
291         for_each_clear_bit_from(i, system_vectors, FIRST_SYSTEM_VECTOR) {
292                 entry = irq_entries_start + IDT_ALIGN * (i - FIRST_EXTERNAL_VECTOR);
293                 set_intr_gate(i, entry);
294         }
295 
296 #ifdef CONFIG_X86_LOCAL_APIC
297         for_each_clear_bit_from(i, system_vectors, NR_VECTORS) {
298                 /*
299                  * Don't set the non assigned system vectors in the
300                  * system_vectors bitmap. Otherwise they show up in
301                  * /proc/interrupts.
302                  */
303                 entry = spurious_entries_start + IDT_ALIGN * (i - FIRST_SYSTEM_VECTOR);
304                 set_intr_gate(i, entry);
305         }
306 #endif
307         /* Map IDT into CPU entry area and reload it. */
308         idt_map_in_cea();
309         load_idt(&idt_descr);
310 
311         /* Make the IDT table read only */
312         set_memory_ro((unsigned long)&idt_table, 1);
313 
314         idt_setup_done = true;
315 }
316 
317 /**
318  * idt_setup_early_handler - Initializes the idt table with early handlers
319  */
320 void __init idt_setup_early_handler(void)
321 {
322         int i;
323 
324         for (i = 0; i < NUM_EXCEPTION_VECTORS; i++)
325                 set_intr_gate(i, early_idt_handler_array[i]);
326 #ifdef CONFIG_X86_32
327         for ( ; i < NR_VECTORS; i++)
328                 set_intr_gate(i, early_ignore_irq);
329 #endif
330         load_idt(&idt_descr);
331 }
332 
333 /**
334  * idt_invalidate - Invalidate interrupt descriptor table
335  */
336 void idt_invalidate(void)
337 {
338         static const struct desc_ptr idt = { .address = 0, .size = 0 };
339 
340         load_idt(&idt);
341 }
342 
343 void __init idt_install_sysvec(unsigned int n, const void *function)
344 {
345         if (WARN_ON(n < FIRST_SYSTEM_VECTOR))
346                 return;
347 
348         if (WARN_ON(idt_setup_done))
349                 return;
350 
351         if (!WARN_ON(test_and_set_bit(n, system_vectors)))
352                 set_intr_gate(n, function);
353 }
354 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php