2019-06-03 07:44:59 +02:00
// SPDX-License-Identifier: GPL-2.0-only
2017-08-28 08:47:43 +02:00
/*
* Interrupt descriptor table related code
*/
# include <linux/interrupt.h>
2020-05-28 16:53:19 +02:00
# include <asm/cpu_entry_area.h>
2020-05-28 16:53:20 +02:00
# include <asm/set_memory.h>
2017-08-28 08:47:49 +02:00
# include <asm/traps.h>
# include <asm/proto.h>
2017-08-28 08:47:43 +02:00
# include <asm/desc.h>
2018-07-29 12:15:33 +02:00
# include <asm/hw_irq.h>
2017-08-28 08:47:43 +02:00
2017-08-28 08:47:49 +02:00
# 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 )
2019-04-14 17:59:45 +02:00
/*
* Interrupt gate with interrupt stack . The _ist index is the index in
* the tss . ist [ ] array , but for the descriptor it needs to start at 1.
*/
2017-08-28 08:47:49 +02:00
# define ISTG(_vector, _addr, _ist) \
2019-04-14 17:59:45 +02:00
G ( _vector , _addr , _ist + 1 , GATE_INTERRUPT , DPL0 , __KERNEL_CS )
2017-08-28 08:47:49 +02:00
/* Task gate */
# define TSKG(_vector, _gdt) \
G ( _vector , NULL , DEFAULT_STACK , GATE_TASK , DPL0 , _gdt < < 3 )
2020-05-28 16:53:18 +02:00
# define IDT_TABLE_SIZE (IDT_ENTRIES * sizeof(gate_desc))
2020-04-28 11:38:23 +02:00
static bool idt_setup_done __initdata ;
2017-08-28 08:47:50 +02:00
/*
* Early traps running on the DEFAULT_STACK because the other interrupt
* stacks work only after cpu_init ( ) .
*/
2017-12-21 16:18:21 -08:00
static const __initconst struct idt_data early_idts [ ] = {
2020-02-25 23:33:26 +01:00
INTG ( X86_TRAP_DB , asm_exc_debug ) ,
2020-02-25 23:16:16 +01:00
SYSG ( X86_TRAP_BP , asm_exc_int3 ) ,
2020-05-28 16:53:17 +02:00
2017-08-28 08:47:50 +02:00
# ifdef CONFIG_X86_32
2020-05-28 16:53:17 +02:00
/*
* Not possible on 64 - bit . See idt_setup_early_pf ( ) for details .
*/
2020-05-21 22:05:28 +02:00
INTG ( X86_TRAP_PF , asm_exc_page_fault ) ,
2017-08-28 08:47:50 +02:00
# endif
} ;
2017-08-28 08:47:53 +02:00
/*
* The default IDT entries which are set up in trap_init ( ) before
* cpu_init ( ) is invoked . Interrupt stacks cannot be used at that point and
* the traps which use them are reinitialized with IST after cpu_init ( ) has
* set up TSS .
*/
2017-12-21 16:18:21 -08:00
static const __initconst struct idt_data def_idts [ ] = {
2020-02-25 23:16:14 +01:00
INTG ( X86_TRAP_DE , asm_exc_divide_error ) ,
2020-02-25 23:33:25 +01:00
INTG ( X86_TRAP_NMI , asm_exc_nmi ) ,
2020-02-25 23:16:17 +01:00
INTG ( X86_TRAP_BR , asm_exc_bounds ) ,
2020-02-25 23:16:18 +01:00
INTG ( X86_TRAP_UD , asm_exc_invalid_op ) ,
2020-02-25 23:16:19 +01:00
INTG ( X86_TRAP_NM , asm_exc_device_not_available ) ,
2020-02-25 23:16:20 +01:00
INTG ( X86_TRAP_OLD_MF , asm_exc_coproc_segment_overrun ) ,
2020-02-25 23:16:22 +01:00
INTG ( X86_TRAP_TS , asm_exc_invalid_tss ) ,
2020-02-25 23:16:23 +01:00
INTG ( X86_TRAP_NP , asm_exc_segment_not_present ) ,
2020-02-25 23:16:24 +01:00
INTG ( X86_TRAP_SS , asm_exc_stack_segment ) ,
2020-02-25 23:16:25 +01:00
INTG ( X86_TRAP_GP , asm_exc_general_protection ) ,
2020-02-25 23:16:26 +01:00
INTG ( X86_TRAP_SPURIOUS , asm_exc_spurious_interrupt_bug ) ,
2020-02-25 23:16:27 +01:00
INTG ( X86_TRAP_MF , asm_exc_coprocessor_error ) ,
2020-02-25 23:16:28 +01:00
INTG ( X86_TRAP_AC , asm_exc_alignment_check ) ,
2020-02-25 23:16:29 +01:00
INTG ( X86_TRAP_XF , asm_exc_simd_coprocessor_error ) ,
2017-08-28 08:47:53 +02:00
# ifdef CONFIG_X86_32
TSKG ( X86_TRAP_DF , GDT_ENTRY_DOUBLEFAULT_TSS ) ,
# else
2020-02-25 23:33:31 +01:00
INTG ( X86_TRAP_DF , asm_exc_double_fault ) ,
2017-08-28 08:47:53 +02:00
# endif
2020-02-25 23:33:26 +01:00
INTG ( X86_TRAP_DB , asm_exc_debug ) ,
2017-08-28 08:47:53 +02:00
# ifdef CONFIG_X86_MCE
2020-02-25 23:33:23 +01:00
INTG ( X86_TRAP_MC , asm_exc_machine_check ) ,
2017-08-28 08:47:53 +02:00
# endif
2020-02-25 23:16:15 +01:00
SYSG ( X86_TRAP_OF , asm_exc_overflow ) ,
2017-08-28 08:47:53 +02:00
# if defined(CONFIG_IA32_EMULATION)
SYSG ( IA32_SYSCALL_VECTOR , entry_INT80_compat ) ,
# elif defined(CONFIG_X86_32)
SYSG ( IA32_SYSCALL_VECTOR , entry_INT80_32 ) ,
# endif
} ;
2017-08-28 08:47:54 +02:00
/*
* The APIC and SMP idt entries
*/
2017-12-21 16:18:21 -08:00
static const __initconst struct idt_data apic_idts [ ] = {
2017-08-28 08:47:54 +02:00
# ifdef CONFIG_SMP
2020-05-21 22:05:45 +02:00
INTG ( RESCHEDULE_VECTOR , asm_sysvec_reschedule_ipi ) ,
2020-05-21 22:05:40 +02:00
INTG ( CALL_FUNCTION_VECTOR , asm_sysvec_call_function ) ,
INTG ( CALL_FUNCTION_SINGLE_VECTOR , asm_sysvec_call_function_single ) ,
INTG ( IRQ_MOVE_CLEANUP_VECTOR , asm_sysvec_irq_move_cleanup ) ,
INTG ( REBOOT_VECTOR , asm_sysvec_reboot ) ,
2017-08-28 08:47:54 +02:00
# endif
# ifdef CONFIG_X86_THERMAL_VECTOR
2020-05-21 22:05:41 +02:00
INTG ( THERMAL_APIC_VECTOR , asm_sysvec_thermal ) ,
2017-08-28 08:47:54 +02:00
# endif
# ifdef CONFIG_X86_MCE_THRESHOLD
2020-05-21 22:05:41 +02:00
INTG ( THRESHOLD_APIC_VECTOR , asm_sysvec_threshold ) ,
2017-08-28 08:47:54 +02:00
# endif
# ifdef CONFIG_X86_MCE_AMD
2020-05-21 22:05:41 +02:00
INTG ( DEFERRED_ERROR_VECTOR , asm_sysvec_deferred_error ) ,
2017-08-28 08:47:54 +02:00
# endif
# ifdef CONFIG_X86_LOCAL_APIC
2020-05-21 22:05:41 +02:00
INTG ( LOCAL_TIMER_VECTOR , asm_sysvec_apic_timer_interrupt ) ,
INTG ( X86_PLATFORM_IPI_VECTOR , asm_sysvec_x86_platform_ipi ) ,
2017-08-28 08:47:54 +02:00
# ifdef CONFIG_HAVE_KVM
2020-05-21 22:05:42 +02:00
INTG ( POSTED_INTR_VECTOR , asm_sysvec_kvm_posted_intr_ipi ) ,
INTG ( POSTED_INTR_WAKEUP_VECTOR , asm_sysvec_kvm_posted_intr_wakeup_ipi ) ,
INTG ( POSTED_INTR_NESTED_VECTOR , asm_sysvec_kvm_posted_intr_nested_ipi ) ,
2017-08-28 08:47:54 +02:00
# endif
# ifdef CONFIG_IRQ_WORK
2020-05-21 22:05:41 +02:00
INTG ( IRQ_WORK_VECTOR , asm_sysvec_irq_work ) ,
# endif
INTG ( SPURIOUS_APIC_VECTOR , asm_sysvec_spurious_apic_interrupt ) ,
INTG ( ERROR_APIC_VECTOR , asm_sysvec_error_interrupt ) ,
2017-08-28 08:47:54 +02:00
# endif
} ;
2020-05-28 16:53:20 +02:00
/* Must be page-aligned because the real IDT is used in the cpu entry area */
static gate_desc idt_table [ IDT_ENTRIES ] __page_aligned_bss ;
2017-08-28 08:47:43 +02:00
2020-06-19 16:51:02 -04:00
static struct desc_ptr idt_descr __ro_after_init = {
2020-05-28 16:53:18 +02:00
. size = IDT_TABLE_SIZE - 1 ,
2017-08-28 08:47:43 +02:00
. address = ( unsigned long ) idt_table ,
} ;
2020-05-28 16:53:20 +02:00
void load_current_idt ( void )
{
lockdep_assert_irqs_disabled ( ) ;
load_idt ( & idt_descr ) ;
}
# ifdef CONFIG_X86_F00F_BUG
bool idt_is_f00f_address ( unsigned long address )
{
return ( ( address - idt_descr . address ) > > 3 ) = = 6 ;
}
2017-08-28 08:47:43 +02:00
# endif
2017-08-28 08:47:46 +02:00
2020-05-28 16:53:16 +02:00
static __init void
2017-08-28 08:47:57 +02:00
idt_setup_from_table ( gate_desc * idt , const struct idt_data * t , int size , bool sys )
2017-08-28 08:47:49 +02:00
{
gate_desc desc ;
for ( ; size > 0 ; t + + , size - - ) {
idt_init_desc ( & desc , t ) ;
write_idt_entry ( idt , t - > vector , & desc ) ;
2017-08-28 08:47:57 +02:00
if ( sys )
2017-09-13 23:29:26 +02:00
set_bit ( t - > vector , system_vectors ) ;
2017-08-28 08:47:49 +02:00
}
}
2020-05-28 16:53:16 +02:00
static __init void set_intr_gate ( unsigned int n , const void * addr )
2017-08-28 08:47:59 +02:00
{
struct idt_data data ;
2020-09-07 15:15:29 +02:00
init_idt_data ( & data , n , addr ) ;
2017-08-28 08:47:59 +02:00
idt_setup_from_table ( idt_table , & data , 1 , false ) ;
}
2017-08-28 08:47:50 +02:00
/**
* idt_setup_early_traps - Initialize the idt table with early traps
*
* On X8664 these traps do not use interrupt stacks as they can ' t work
* before cpu_init ( ) is invoked and sets up TSS . The IST variants are
* installed after that .
*/
void __init idt_setup_early_traps ( void )
{
2017-08-28 08:47:57 +02:00
idt_setup_from_table ( idt_table , early_idts , ARRAY_SIZE ( early_idts ) ,
true ) ;
2017-08-28 08:47:50 +02:00
load_idt ( & idt_descr ) ;
}
2017-08-28 08:47:53 +02:00
/**
* idt_setup_traps - Initialize the idt table with default traps
*/
void __init idt_setup_traps ( void )
{
2017-08-28 08:47:57 +02:00
idt_setup_from_table ( idt_table , def_idts , ARRAY_SIZE ( def_idts ) , true ) ;
2017-08-28 08:47:53 +02:00
}
2017-08-28 08:47:50 +02:00
# ifdef CONFIG_X86_64
2020-05-28 16:53:20 +02:00
/*
* Early traps running on the DEFAULT_STACK because the other interrupt
* stacks work only after cpu_init ( ) .
*/
static const __initconst struct idt_data early_pf_idts [ ] = {
INTG ( X86_TRAP_PF , asm_exc_page_fault ) ,
} ;
/*
* The exceptions which use Interrupt stacks . They are setup after
* cpu_init ( ) when the TSS has been initialized .
*/
static const __initconst struct idt_data ist_idts [ ] = {
2020-09-07 15:15:47 +02:00
ISTG ( X86_TRAP_DB , asm_exc_debug , IST_INDEX_DB ) ,
ISTG ( X86_TRAP_NMI , asm_exc_nmi , IST_INDEX_NMI ) ,
ISTG ( X86_TRAP_DF , asm_exc_double_fault , IST_INDEX_DF ) ,
2020-05-28 16:53:20 +02:00
# ifdef CONFIG_X86_MCE
2020-09-07 15:15:47 +02:00
ISTG ( X86_TRAP_MC , asm_exc_machine_check , IST_INDEX_MCE ) ,
# endif
# ifdef CONFIG_AMD_MEM_ENCRYPT
ISTG ( X86_TRAP_VC , asm_exc_vmm_communication , IST_INDEX_VC ) ,
2020-05-28 16:53:20 +02:00
# endif
} ;
2017-08-28 08:47:50 +02:00
/**
* idt_setup_early_pf - Initialize the idt table with early pagefault handler
*
* On X8664 this does not use interrupt stacks as they can ' t work before
* cpu_init ( ) is invoked and sets up TSS . The IST variant is installed
* after that .
*
2020-05-28 16:53:17 +02:00
* Note , that X86_64 cannot install the real # PF handler in
2021-03-18 15:28:01 +01:00
* idt_setup_early_traps ( ) because the memory initialization needs the # PF
2020-05-28 16:53:17 +02:00
* handler from the early_idt_handler_array to initialize the early page
* tables .
2017-08-28 08:47:50 +02:00
*/
void __init idt_setup_early_pf ( void )
{
idt_setup_from_table ( idt_table , early_pf_idts ,
2017-08-28 08:47:57 +02:00
ARRAY_SIZE ( early_pf_idts ) , true ) ;
2017-08-28 08:47:50 +02:00
}
2017-08-28 08:47:51 +02:00
2017-08-28 08:47:52 +02:00
/**
* idt_setup_ist_traps - Initialize the idt table with traps using IST
*/
void __init idt_setup_ist_traps ( void )
{
2017-08-28 08:47:57 +02:00
idt_setup_from_table ( idt_table , ist_idts , ARRAY_SIZE ( ist_idts ) , true ) ;
2017-08-28 08:47:52 +02:00
}
2017-08-28 08:47:50 +02:00
# endif
2020-05-28 16:53:19 +02:00
static void __init idt_map_in_cea ( void )
{
/*
* Set the IDT descriptor to a fixed read - only location in the cpu
* entry area , so that the " sidt " instruction will not leak the
* location of the kernel , and to defend the IDT against arbitrary
* memory write vulnerabilities .
*/
cea_set_pte ( CPU_ENTRY_AREA_RO_IDT_VADDR , __pa_symbol ( idt_table ) ,
PAGE_KERNEL_RO ) ;
idt_descr . address = CPU_ENTRY_AREA_RO_IDT ;
}
2017-08-28 08:47:54 +02:00
/**
* idt_setup_apic_and_irq_gates - Setup APIC / SMP and normal interrupt gates
*/
void __init idt_setup_apic_and_irq_gates ( void )
{
2017-08-28 08:47:55 +02:00
int i = FIRST_EXTERNAL_VECTOR ;
void * entry ;
2017-08-28 08:47:57 +02:00
idt_setup_from_table ( idt_table , apic_idts , ARRAY_SIZE ( apic_idts ) , true ) ;
2017-08-28 08:47:55 +02:00
2017-09-13 23:29:26 +02:00
for_each_clear_bit_from ( i , system_vectors , FIRST_SYSTEM_VECTOR ) {
2017-08-28 08:47:55 +02:00
entry = irq_entries_start + 8 * ( i - FIRST_EXTERNAL_VECTOR ) ;
set_intr_gate ( i , entry ) ;
}
# ifdef CONFIG_X86_LOCAL_APIC
2018-05-23 10:35:55 +08:00
for_each_clear_bit_from ( i , system_vectors , NR_VECTORS ) {
2020-04-28 11:38:24 +02:00
/*
* Don ' t set the non assigned system vectors in the
* system_vectors bitmap . Otherwise they show up in
* / proc / interrupts .
*/
2019-06-28 13:11:54 +02:00
entry = spurious_entries_start + 8 * ( i - FIRST_SYSTEM_VECTOR ) ;
set_intr_gate ( i , entry ) ;
2017-08-28 08:47:55 +02:00
}
2018-05-23 10:35:55 +08:00
# endif
2020-05-28 16:53:19 +02:00
/* Map IDT into CPU entry area and reload it. */
idt_map_in_cea ( ) ;
load_idt ( & idt_descr ) ;
2020-05-28 16:53:20 +02:00
/* Make the IDT table read only */
set_memory_ro ( ( unsigned long ) & idt_table , 1 ) ;
2020-04-28 11:38:23 +02:00
idt_setup_done = true ;
2017-08-28 08:47:54 +02:00
}
2017-08-28 08:47:47 +02:00
/**
* idt_setup_early_handler - Initializes the idt table with early handlers
*/
void __init idt_setup_early_handler ( void )
{
int i ;
for ( i = 0 ; i < NUM_EXCEPTION_VECTORS ; i + + )
set_intr_gate ( i , early_idt_handler_array [ i ] ) ;
2017-08-28 08:47:48 +02:00
# ifdef CONFIG_X86_32
for ( ; i < NR_VECTORS ; i + + )
set_intr_gate ( i , early_ignore_irq ) ;
# endif
2017-08-28 08:47:47 +02:00
load_idt ( & idt_descr ) ;
}
2017-08-28 08:47:46 +02:00
/**
* idt_invalidate - Invalidate interrupt descriptor table
* @ addr : The virtual address of the ' invalid ' IDT
*/
void idt_invalidate ( void * addr )
{
struct desc_ptr idt = { . address = ( unsigned long ) addr , . size = 0 } ;
load_idt ( & idt ) ;
}
2017-08-28 08:47:57 +02:00
2020-04-28 11:38:23 +02:00
void __init alloc_intr_gate ( unsigned int n , const void * addr )
2017-08-28 08:47:57 +02:00
{
2020-04-28 11:38:23 +02:00
if ( WARN_ON ( n < FIRST_SYSTEM_VECTOR ) )
return ;
if ( WARN_ON ( idt_setup_done ) )
return ;
if ( ! WARN_ON ( test_and_set_bit ( n , system_vectors ) ) )
2017-08-28 08:47:58 +02:00
set_intr_gate ( n , addr ) ;
2017-08-28 08:47:57 +02:00
}