2005-04-16 15:20:36 -07:00
/*
2007-11-28 20:19:38 +09:00
* arch / sh / mm / extable_64 . c
2005-04-16 15:20:36 -07:00
*
* Copyright ( C ) 2003 Richard Curnow
* Copyright ( C ) 2003 , 2004 Paul Mundt
*
* Cloned from the 2.5 SH version . .
2007-11-28 20:19:38 +09:00
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
2005-04-16 15:20:36 -07:00
*/
2017-07-10 15:51:58 -07:00
# include <linux/bsearch.h>
2005-04-16 15:20:36 -07:00
# include <linux/rwsem.h>
2016-07-23 14:01:45 -04:00
# include <linux/extable.h>
2016-12-24 11:46:01 -08:00
# include <linux/uaccess.h>
2005-04-16 15:20:36 -07:00
extern unsigned long copy_user_memcpy , copy_user_memcpy_end ;
extern void __copy_user_fixup ( void ) ;
static const struct exception_table_entry __copy_user_fixup_ex = {
. fixup = ( unsigned long ) & __copy_user_fixup ,
} ;
2007-11-28 20:19:38 +09:00
/*
* Some functions that may trap due to a bad user - mode address have too
* many loads and stores in them to make it at all practical to label
* each one and put them all in the main exception table .
*
* In particular , the fast memcpy routine is like this . It ' s fix - up is
* just to fall back to a slow byte - at - a - time copy , which is handled the
* conventional way . So it ' s functionally OK to just handle any trap
* occurring in the fast memcpy with that fixup .
*/
2005-04-16 15:20:36 -07:00
static const struct exception_table_entry * check_exception_ranges ( unsigned long addr )
{
if ( ( addr > = ( unsigned long ) & copy_user_memcpy ) & &
( addr < = ( unsigned long ) & copy_user_memcpy_end ) )
return & __copy_user_fixup_ex ;
return NULL ;
}
2017-07-10 15:51:58 -07:00
static int cmp_ex_search ( const void * key , const void * elt )
{
const struct exception_table_entry * _elt = elt ;
unsigned long _key = * ( unsigned long * ) key ;
/* avoid overflow */
if ( _key > _elt - > insn )
return 1 ;
if ( _key < _elt - > insn )
return - 1 ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
/* Simple binary search */
const struct exception_table_entry *
2017-07-10 15:51:58 -07:00
search_extable ( const struct exception_table_entry * base ,
const size_t num ,
2005-04-16 15:20:36 -07:00
unsigned long value )
{
const struct exception_table_entry * mid ;
mid = check_exception_ranges ( value ) ;
if ( mid )
return mid ;
2017-07-10 15:51:58 -07:00
return bsearch ( & value , base , num ,
sizeof ( struct exception_table_entry ) , cmp_ex_search ) ;
2005-04-16 15:20:36 -07:00
}
int fixup_exception ( struct pt_regs * regs )
{
const struct exception_table_entry * fixup ;
fixup = search_exception_tables ( regs - > pc ) ;
if ( fixup ) {
regs - > pc = fixup - > fixup ;
return 1 ;
}
return 0 ;
}