2008-01-30 15:31:41 +03:00
# include <linux/module.h>
# include <asm/uaccess.h>
2016-04-02 17:01:33 +03:00
# include <asm/traps.h>
2008-01-30 15:31:41 +03:00
2016-02-17 21:20:12 +03:00
typedef bool ( * ex_handler_t ) ( const struct exception_table_entry * ,
struct pt_regs * , int ) ;
2012-04-21 04:12:48 +04:00
static inline unsigned long
ex_fixup_addr ( const struct exception_table_entry * x )
{
return ( unsigned long ) & x - > fixup + x - > fixup ;
}
2016-02-17 21:20:12 +03: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 15:31:41 +03:00
2016-02-17 21:20:12 +03:00
bool ex_handler_default ( const struct exception_table_entry * fixup ,
struct pt_regs * regs , int trapnr )
2008-01-30 15:31:41 +03:00
{
2016-02-17 21:20:12 +03: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 */
current_thread_info ( ) - > uaccess_err = 1 ;
regs - > ip = ex_fixup_addr ( fixup ) ;
return true ;
}
EXPORT_SYMBOL ( ex_handler_ext ) ;
2016-04-02 17:01:37 +03:00
bool ex_handler_rdmsr_unsafe ( const struct exception_table_entry * fixup ,
struct pt_regs * regs , int trapnr )
{
WARN_ONCE ( 1 , " unchecked MSR access error: RDMSR from 0x%x \n " ,
( unsigned int ) regs - > cx ) ;
/* 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 )
{
WARN_ONCE ( 1 , " unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) \n " ,
( unsigned int ) regs - > cx ,
( unsigned int ) regs - > dx , ( unsigned int ) regs - > ax ) ;
/* Pretend that the write succeeded. */
regs - > ip = ex_fixup_addr ( fixup ) ;
return true ;
}
EXPORT_SYMBOL ( ex_handler_wrmsr_unsafe ) ;
2016-04-26 22:23:26 +03: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 21:20:12 +03: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 15:31:41 +03: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 21:20:12 +03:00
e = search_exception_tables ( regs - > ip ) ;
if ( ! e )
return 0 ;
2008-01-30 15:31:41 +03:00
2016-02-17 21:20:12 +03:00
handler = ex_fixup_handler ( e ) ;
return handler ( e , regs , trapnr ) ;
2008-01-30 15:31:41 +03:00
}
2012-04-20 02:24:20 +04:00
2016-04-02 17:01:34 +03:00
extern unsigned int early_recursion_flag ;
2012-04-20 02:24:20 +04:00
/* Restricted version used during very early boot */
2016-04-02 17:01:34 +03:00
void __init early_fixup_exception ( struct pt_regs * regs , int trapnr )
2012-04-20 02:24:20 +04:00
{
2016-04-02 17:01:33 +03:00
/* Ignore early NMIs. */
if ( trapnr = = X86_TRAP_NMI )
2016-04-02 17:01:34 +03:00
return ;
if ( early_recursion_flag > 2 )
goto halt_loop ;
if ( regs - > cs ! = __KERNEL_CS )
goto fail ;
2016-04-02 17:01:33 +03:00
2016-04-04 18:46:22 +03: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 17:01:35 +03:00
if ( fixup_exception ( regs , trapnr ) )
return ;
2016-04-02 17:01:34 +03: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-20 02:24:20 +04:00
}