2008-02-08 04:19:31 -08:00
/* MN10300 Userspace accessor functions
*
* Copyright ( C ) 2007 Matsushita Electric Industrial Co . , Ltd .
* Copyright ( C ) 2007 Red Hat , Inc . All Rights Reserved .
* Written by David Howells ( dhowells @ redhat . com )
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public Licence
* as published by the Free Software Foundation ; either version
* 2 of the Licence , or ( at your option ) any later version .
*/
# include <asm/uaccess.h>
unsigned long
__generic_copy_to_user ( void * to , const void * from , unsigned long n )
{
if ( access_ok ( VERIFY_WRITE , to , n ) )
__copy_user ( to , from , n ) ;
return n ;
}
unsigned long
__generic_copy_from_user ( void * to , const void * from , unsigned long n )
{
if ( access_ok ( VERIFY_READ , from , n ) )
__copy_user_zeroing ( to , from , n ) ;
return n ;
}
/*
* Copy a null terminated string from userspace .
*/
# define __do_strncpy_from_user(dst, src, count, res) \
do { \
int w ; \
asm volatile ( \
" mov %1,%0 \n " \
" cmp 0,%1 \n " \
" beq 2f \n " \
" 0: \n " \
" movbu (%5),%2 \n " \
" 1: \n " \
" movbu %2,(%6) \n " \
" inc %5 \n " \
" inc %6 \n " \
" cmp 0,%2 \n " \
" beq 2f \n " \
" add -1,%1 \n " \
" bne 0b \n " \
" 2: \n " \
" sub %1,%0 \n " \
" 3: \n " \
" .section .fixup, \" ax \" \n " \
" 4: \n " \
" mov %3,%0 \n " \
" jmp 3b \n " \
" .previous \n " \
" .section __ex_table, \" a \" \n " \
" .balign 4 \n " \
" .long 0b,4b \n " \
" .long 1b,4b \n " \
" .previous " \
: " =&r " ( res ) , " =r " ( count ) , " =&r " ( w ) \
: " i " ( - EFAULT ) , " 1 " ( count ) , " a " ( src ) , " a " ( dst ) \
2010-01-08 14:43:16 -08:00
: " memory " , " cc " ) ; \
2008-02-08 04:19:31 -08:00
} while ( 0 )
long
__strncpy_from_user ( char * dst , const char * src , long count )
{
long res ;
__do_strncpy_from_user ( dst , src , count , res ) ;
return res ;
}
long
strncpy_from_user ( char * dst , const char * src , long count )
{
long res = - EFAULT ;
if ( access_ok ( VERIFY_READ , src , 1 ) )
__do_strncpy_from_user ( dst , src , count , res ) ;
return res ;
}
/*
* Clear a userspace memory
*/
# define __do_clear_user(addr, size) \
do { \
int w ; \
asm volatile ( \
" cmp 0,%0 \n " \
" beq 1f \n " \
" clr %1 \n " \
" 0: movbu %1,(%3,%2) \n " \
" inc %3 \n " \
" cmp %0,%3 \n " \
" bne 0b \n " \
" 1: \n " \
" sub %3,%0 \n " \
" 2: \n " \
" .section .fixup, \" ax \" \n " \
" 3: jmp 2b \n " \
" .previous \n " \
" .section __ex_table, \" a \" \n " \
" .balign 4 \n " \
" .long 0b,3b \n " \
" .previous \n " \
: " +r " ( size ) , " =&r " ( w ) \
: " a " ( addr ) , " d " ( 0 ) \
2010-01-08 14:43:16 -08:00
: " memory " , " cc " ) ; \
2008-02-08 04:19:31 -08:00
} while ( 0 )
unsigned long
__clear_user ( void * to , unsigned long n )
{
__do_clear_user ( to , n ) ;
return n ;
}
unsigned long
clear_user ( void * to , unsigned long n )
{
if ( access_ok ( VERIFY_WRITE , to , n ) )
__do_clear_user ( to , n ) ;
return n ;
}
/*
* Return the size of a string ( including the ending 0 )
*
* Return 0 on exception , a value greater than N if too long
*/
long strnlen_user ( const char * s , long n )
{
unsigned long res , w ;
if ( ! __addr_ok ( s ) )
return 0 ;
if ( n < 0 | | n + ( u_long ) s > current_thread_info ( ) - > addr_limit . seg )
n = current_thread_info ( ) - > addr_limit . seg - ( u_long ) s ;
asm volatile (
" 0: cmp %4,%0 \n "
" beq 2f \n "
" 1: movbu (%0,%3),%1 \n "
" inc %0 \n "
" cmp 0,%1 \n "
" beq 3f \n "
" bra 0b \n "
" 2: clr %0 \n "
" 3: \n "
" .section .fixup, \" ax \" \n "
" 4: jmp 2b \n "
" .previous \n "
" .section __ex_table, \" a \" \n "
" .balign 4 \n "
" .long 1b,4b \n "
" .previous \n "
: " =d " ( res ) , " =&r " ( w )
: " 0 " ( 0 ) , " a " ( s ) , " r " ( n )
2010-01-08 14:43:16 -08:00
: " memory " , " cc " ) ;
2008-02-08 04:19:31 -08:00
return res ;
}