2016-09-19 17:04:18 -04:00
# include <linux/extable.h>
2016-12-24 11:46:01 -08:00
# include <linux/uaccess.h>
2017-02-08 18:51:35 +01:00
# include <linux/sched/debug.h>
2016-04-02 07:01:33 -07:00
# include <asm/traps.h>
2016-07-05 00:31:27 +02:00
# include <asm/kdebug.h>
2008-01-30 13:31:41 +01:00
2016-02-17 10:20:12 -08:00
typedef bool ( * ex_handler_t ) ( const struct exception_table_entry * ,
struct pt_regs * , int ) ;
2012-04-20 17:12:48 -07:00
static inline unsigned long
ex_fixup_addr ( const struct exception_table_entry * x )
{
return ( unsigned long ) & x - > fixup + x - > fixup ;
}
2016-02-17 10:20:12 -08:00
static inline ex_handler_t
ex_fixup_handler ( const struct exception_table_entry * x )
{
return ( ex_handler_t ) ( ( unsigned long ) & x - > handler + x - > handler ) ;
}
2008-01-30 13:31:41 +01:00
2016-02-17 10:20:12 -08:00
bool ex_handler_default ( const struct exception_table_entry * fixup ,
struct pt_regs * regs , int trapnr )
2008-01-30 13:31:41 +01:00
{
2016-02-17 10:20:12 -08:00
regs - > ip = ex_fixup_addr ( fixup ) ;
return true ;
}
EXPORT_SYMBOL ( ex_handler_default ) ;
bool ex_handler_fault ( const struct exception_table_entry * fixup ,
struct pt_regs * regs , int trapnr )
{
regs - > ip = ex_fixup_addr ( fixup ) ;
regs - > ax = trapnr ;
return true ;
}
EXPORT_SYMBOL_GPL ( ex_handler_fault ) ;
bool ex_handler_ext ( const struct exception_table_entry * fixup ,
struct pt_regs * regs , int trapnr )
{
/* Special hack for uaccess_err */
2016-07-14 13:22:56 -07:00
current - > thread . uaccess_err = 1 ;
2016-02-17 10:20:12 -08:00
regs - > ip = ex_fixup_addr ( fixup ) ;
return true ;
}
EXPORT_SYMBOL ( ex_handler_ext ) ;
2016-04-02 07:01:37 -07:00
bool ex_handler_rdmsr_unsafe ( const struct exception_table_entry * fixup ,
struct pt_regs * regs , int trapnr )
{
2016-07-05 00:31:27 +02:00
if ( pr_warn_once ( " unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pF) \n " ,
( unsigned int ) regs - > cx , regs - > ip , ( void * ) regs - > ip ) )
show_stack_regs ( regs ) ;
2016-04-02 07:01:37 -07:00
/* Pretend that the read succeeded and returned 0. */
regs - > ip = ex_fixup_addr ( fixup ) ;
regs - > ax = 0 ;
regs - > dx = 0 ;
return true ;
}
EXPORT_SYMBOL ( ex_handler_rdmsr_unsafe ) ;
bool ex_handler_wrmsr_unsafe ( const struct exception_table_entry * fixup ,
struct pt_regs * regs , int trapnr )
{
2016-07-05 00:31:27 +02:00
if ( pr_warn_once ( " unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pF) \n " ,
( unsigned int ) regs - > cx , ( unsigned int ) regs - > dx ,
( unsigned int ) regs - > ax , regs - > ip , ( void * ) regs - > ip ) )
show_stack_regs ( regs ) ;
2016-04-02 07:01:37 -07:00
/* Pretend that the write succeeded. */
regs - > ip = ex_fixup_addr ( fixup ) ;
return true ;
}
EXPORT_SYMBOL ( ex_handler_wrmsr_unsafe ) ;
2016-04-26 12:23:26 -07:00
bool ex_handler_clear_fs ( const struct exception_table_entry * fixup ,
struct pt_regs * regs , int trapnr )
{
if ( static_cpu_has ( X86_BUG_NULL_SEG ) )
asm volatile ( " mov %0, %%fs " : : " rm " ( __USER_DS ) ) ;
asm volatile ( " mov %0, %%fs " : : " rm " ( 0 ) ) ;
return ex_handler_default ( fixup , regs , trapnr ) ;
}
EXPORT_SYMBOL ( ex_handler_clear_fs ) ;
2016-02-17 10:20:12 -08:00
bool ex_has_fault_handler ( unsigned long ip )
{
const struct exception_table_entry * e ;
ex_handler_t handler ;
e = search_exception_tables ( ip ) ;
if ( ! e )
return false ;
handler = ex_fixup_handler ( e ) ;
return handler = = ex_handler_fault ;
}
int fixup_exception ( struct pt_regs * regs , int trapnr )
{
const struct exception_table_entry * e ;
ex_handler_t handler ;
2008-01-30 13:31:41 +01:00
# ifdef CONFIG_PNPBIOS
if ( unlikely ( SEGMENT_IS_PNP_CODE ( regs - > cs ) ) ) {
extern u32 pnp_bios_fault_eip , pnp_bios_fault_esp ;
extern u32 pnp_bios_is_utter_crap ;
pnp_bios_is_utter_crap = 1 ;
printk ( KERN_CRIT " PNPBIOS fault.. attempting recovery. \n " ) ;
__asm__ volatile (
" movl %0, %%esp \n \t "
" jmp *%1 \n \t "
: : " g " ( pnp_bios_fault_esp ) , " g " ( pnp_bios_fault_eip ) ) ;
panic ( " do_trap: can't hit this " ) ;
}
# endif
2016-02-17 10:20:12 -08:00
e = search_exception_tables ( regs - > ip ) ;
if ( ! e )
return 0 ;
2008-01-30 13:31:41 +01:00
2016-02-17 10:20:12 -08:00
handler = ex_fixup_handler ( e ) ;
return handler ( e , regs , trapnr ) ;
2008-01-30 13:31:41 +01:00
}
2012-04-19 15:24:20 -07:00
2016-04-02 07:01:34 -07:00
extern unsigned int early_recursion_flag ;
2012-04-19 15:24:20 -07:00
/* Restricted version used during very early boot */
2016-04-02 07:01:34 -07:00
void __init early_fixup_exception ( struct pt_regs * regs , int trapnr )
2012-04-19 15:24:20 -07:00
{
2016-04-02 07:01:33 -07:00
/* Ignore early NMIs. */
if ( trapnr = = X86_TRAP_NMI )
2016-04-02 07:01:34 -07:00
return ;
if ( early_recursion_flag > 2 )
goto halt_loop ;
2016-11-19 18:42:40 -08:00
/*
* Old CPUs leave the high bits of CS on the stack
* undefined . I ' m not sure which CPUs do this , but at least
* the 486 DX works this way .
*/
if ( ( regs - > cs & 0xFFFF ) ! = __KERNEL_CS )
2016-04-02 07:01:34 -07:00
goto fail ;
2016-04-02 07:01:33 -07:00
2016-04-04 08:46:22 -07:00
/*
* The full exception fixup machinery is available as soon as
* the early IDT is loaded . This means that it is the
* responsibility of extable users to either function correctly
* when handlers are invoked early or to simply avoid causing
* exceptions before they ' re ready to handle them .
*
* This is better than filtering which handlers can be used ,
* because refusing to call a handler here is guaranteed to
* result in a hard - to - debug panic .
*
* Keep in mind that not all vectors actually get here . Early
* fage faults , for example , are special .
*/
2016-04-02 07:01:35 -07:00
if ( fixup_exception ( regs , trapnr ) )
return ;
2016-04-02 07:01:34 -07:00
2017-06-12 13:52:46 +02:00
if ( fixup_bug ( regs , trapnr ) )
return ;
2016-04-02 07:01:34 -07:00
fail :
early_printk ( " PANIC: early exception 0x%02x IP %lx:%lx error %lx cr2 0x%lx \n " ,
( unsigned ) trapnr , ( unsigned long ) regs - > cs , regs - > ip ,
regs - > orig_ax , read_cr2 ( ) ) ;
show_regs ( regs ) ;
halt_loop :
while ( true )
halt ( ) ;
2012-04-19 15:24:20 -07:00
}