2005-04-16 15:20:36 -07:00
/*
* linux / arch / alpha / mm / extable . c
*/
# include <linux/module.h>
2009-04-30 15:08:47 -07:00
# include <linux/sort.h>
2005-04-16 15:20:36 -07:00
# include <asm/uaccess.h>
2009-04-30 15:08:47 -07:00
static inline unsigned long ex_to_addr ( const struct exception_table_entry * x )
{
return ( unsigned long ) & x - > insn + x - > insn ;
}
static void swap_ex ( void * a , void * b , int size )
{
struct exception_table_entry * ex_a = a , * ex_b = b ;
unsigned long addr_a = ex_to_addr ( ex_a ) , addr_b = ex_to_addr ( ex_b ) ;
unsigned int t = ex_a - > fixup . unit ;
ex_a - > fixup . unit = ex_b - > fixup . unit ;
ex_b - > fixup . unit = t ;
ex_a - > insn = ( int ) ( addr_b - ( unsigned long ) & ex_a - > insn ) ;
ex_b - > insn = ( int ) ( addr_a - ( unsigned long ) & ex_b - > insn ) ;
}
/*
* The exception table needs to be sorted so that the binary
* search that we use to find entries in it works properly .
* This is used both for the kernel exception table and for
* the exception tables of modules that get loaded .
*/
static int cmp_ex ( const void * a , const void * b )
{
const struct exception_table_entry * x = a , * y = b ;
/* avoid overflow */
if ( ex_to_addr ( x ) > ex_to_addr ( y ) )
return 1 ;
if ( ex_to_addr ( x ) < ex_to_addr ( y ) )
return - 1 ;
return 0 ;
}
2005-04-16 15:20:36 -07:00
void sort_extable ( struct exception_table_entry * start ,
struct exception_table_entry * finish )
{
2009-04-30 15:08:47 -07:00
sort ( start , finish - start , sizeof ( struct exception_table_entry ) ,
cmp_ex , swap_ex ) ;
2005-04-16 15:20:36 -07:00
}
2009-06-12 21:47:03 -06:00
# ifdef CONFIG_MODULES
/*
* Any entry referring to the module init will be at the beginning or
* the end .
*/
void trim_init_extable ( struct module * m )
{
/*trim the beginning*/
while ( m - > num_exentries & &
within_module_init ( ex_to_addr ( & m - > extable [ 0 ] ) , m ) ) {
m - > extable + + ;
m - > num_exentries - - ;
}
/*trim the end*/
while ( m - > num_exentries & &
within_module_init ( ex_to_addr ( & m - > extable [ m - > num_exentries - 1 ] ) ,
m ) )
m - > num_exentries - - ;
}
# endif /* CONFIG_MODULES */
2005-04-16 15:20:36 -07:00
const struct exception_table_entry *
search_extable ( const struct exception_table_entry * first ,
const struct exception_table_entry * last ,
unsigned long value )
{
while ( first < = last ) {
const struct exception_table_entry * mid ;
unsigned long mid_value ;
mid = ( last - first ) / 2 + first ;
2009-04-30 15:08:47 -07:00
mid_value = ex_to_addr ( mid ) ;
2005-04-16 15:20:36 -07:00
if ( mid_value = = value )
return mid ;
else if ( mid_value < value )
first = mid + 1 ;
else
last = mid - 1 ;
}
return NULL ;
}