2005-04-17 02:20:36 +04:00
/*
* Handle unaligned accesses by emulation .
*
* 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 .
*
* Copyright ( C ) 1996 , 1998 , 1999 , 2002 by Ralf Baechle
* Copyright ( C ) 1999 Silicon Graphics , Inc .
2013-12-19 20:41:05 +04:00
* Copyright ( C ) 2014 Imagination Technologies Ltd .
2005-04-17 02:20:36 +04:00
*
* This file contains exception handler for address error exception with the
* special capability to execute faulting instructions in software . The
* handler does not try to handle the case when the program counter points
* to an address not aligned to a word boundary .
*
* Putting data to unaligned addresses is a bad practice even on Intel where
* only the performance is affected . Much worse is that such code is non -
* portable . Due to several programs that die on MIPS due to alignment
* problems I decided to implement this handler anyway though I originally
* didn ' t intend to do this at all for user code .
*
* For now I enable fixing of address errors by default to make life easier .
* I however intend to disable this somewhen in the future when the alignment
2013-01-22 15:59:30 +04:00
* problems with user programs have been fixed . For programmers this is the
2005-04-17 02:20:36 +04:00
* right way to go .
*
* Fixing address errors is a per process option . The option is inherited
2013-01-22 15:59:30 +04:00
* across fork ( 2 ) and execve ( 2 ) calls . If you really want to use the
2005-04-17 02:20:36 +04:00
* option in your user programs - I discourage the use of the software
* emulation strongly - use the following code in your userland stuff :
*
* # include < sys / sysmips . h >
*
* . . .
* sysmips ( MIPS_FIXADE , x ) ;
* . . .
*
* The argument x is 0 for disabling software emulation , enabled otherwise .
*
* Below a little program to play around with this feature .
*
* # include < stdio . h >
* # include < sys / sysmips . h >
*
* struct foo {
2013-01-22 15:59:30 +04:00
* unsigned char bar [ 8 ] ;
2005-04-17 02:20:36 +04:00
* } ;
*
* main ( int argc , char * argv [ ] )
* {
2013-01-22 15:59:30 +04:00
* struct foo x = { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 } ;
* unsigned int * p = ( unsigned int * ) ( x . bar + 3 ) ;
* int i ;
2005-04-17 02:20:36 +04:00
*
2013-01-22 15:59:30 +04:00
* if ( argc > 1 )
* sysmips ( MIPS_FIXADE , atoi ( argv [ 1 ] ) ) ;
2005-04-17 02:20:36 +04:00
*
2013-01-22 15:59:30 +04:00
* printf ( " *p = %08lx \n " , * p ) ;
2005-04-17 02:20:36 +04:00
*
2013-01-22 15:59:30 +04:00
* * p = 0xdeadface ;
2005-04-17 02:20:36 +04:00
*
2013-01-22 15:59:30 +04:00
* for ( i = 0 ; i < = 7 ; i + + )
* printf ( " %02x " , x . bar [ i ] ) ;
* printf ( " \n " ) ;
2005-04-17 02:20:36 +04:00
* }
*
* Coprocessor loads are not supported ; I think this case is unimportant
* in the practice .
*
* TODO : Handle ndc ( attempted store to doubleword in uncached memory )
2013-01-22 15:59:30 +04:00
* exception for the R6000 .
* A store crossing a page boundary might be executed only partially .
* Undo the partial store in this case .
2005-04-17 02:20:36 +04:00
*/
2013-05-29 03:07:19 +04:00
# include <linux/context_tracking.h>
2005-04-17 02:20:36 +04:00
# include <linux/mm.h>
# include <linux/signal.h>
# include <linux/smp.h>
Detach sched.h from mm.h
First thing mm.h does is including sched.h solely for can_do_mlock() inline
function which has "current" dereference inside. By dealing with can_do_mlock()
mm.h can be detached from sched.h which is good. See below, why.
This patch
a) removes unconditional inclusion of sched.h from mm.h
b) makes can_do_mlock() normal function in mm/mlock.c
c) exports can_do_mlock() to not break compilation
d) adds sched.h inclusions back to files that were getting it indirectly.
e) adds less bloated headers to some files (asm/signal.h, jiffies.h) that were
getting them indirectly
Net result is:
a) mm.h users would get less code to open, read, preprocess, parse, ... if
they don't need sched.h
b) sched.h stops being dependency for significant number of files:
on x86_64 allmodconfig touching sched.h results in recompile of 4083 files,
after patch it's only 3744 (-8.3%).
Cross-compile tested on
all arm defconfigs, all mips defconfigs, all powerpc defconfigs,
alpha alpha-up
arm
i386 i386-up i386-defconfig i386-allnoconfig
ia64 ia64-up
m68k
mips
parisc parisc-up
powerpc powerpc-up
s390 s390-up
sparc sparc-up
sparc64 sparc64-up
um-x86_64
x86_64 x86_64-up x86_64-defconfig x86_64-allnoconfig
as well as my two usual configs.
Signed-off-by: Alexey Dobriyan <adobriyan@gmail.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-05-21 01:22:52 +04:00
# include <linux/sched.h>
2007-06-29 19:55:48 +04:00
# include <linux/debugfs.h>
2010-10-12 15:37:21 +04:00
# include <linux/perf_event.h>
2005-04-17 02:20:36 +04:00
# include <asm/asm.h>
# include <asm/branch.h>
# include <asm/byteorder.h>
2009-11-24 04:24:58 +03:00
# include <asm/cop2.h>
2013-03-25 21:09:02 +04:00
# include <asm/fpu.h>
# include <asm/fpu_emulator.h>
2005-04-17 02:20:36 +04:00
# include <asm/inst.h>
# include <asm/uaccess.h>
2013-01-22 15:59:30 +04:00
# define STR(x) __STR(x)
2005-04-17 02:20:36 +04:00
# define __STR(x) #x
2007-06-29 19:55:48 +04:00
enum {
UNALIGNED_ACTION_QUIET ,
UNALIGNED_ACTION_SIGNAL ,
UNALIGNED_ACTION_SHOW ,
} ;
# ifdef CONFIG_DEBUG_FS
static u32 unaligned_instructions ;
static u32 unaligned_action ;
# else
# define unaligned_action UNALIGNED_ACTION_QUIET
2005-04-17 02:20:36 +04:00
# endif
2007-06-29 19:55:48 +04:00
extern void show_registers ( struct pt_regs * regs ) ;
2005-04-17 02:20:36 +04:00
2013-03-25 22:18:07 +04:00
# ifdef __BIG_ENDIAN
2015-03-09 17:54:50 +03:00
# define _LoadHW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( " .set \t noat \n " \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _lb ( " %0 " , " 0(%2) " ) " \n " \
" 2: \t " type # # _lbu ( " $1 " , " 1(%2) " ) " \n \t " \
2013-03-25 22:18:07 +04:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" li \t %1, 0 \n " \
" 3: \t .set \t at \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %1, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2013-03-25 22:18:07 +04:00
2014-10-28 13:42:23 +03:00
# ifndef CONFIG_CPU_MIPSR6
2015-03-09 17:54:50 +03:00
# define _LoadW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _lwl ( " %0 " , " (%2) " ) " \n " \
" 2: \t " type # # _lwr ( " %0 " , " 3(%2) " ) " \n \t " \
2013-03-25 22:18:07 +04:00
" li \t %1, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %1, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# else
/* MIPSR6 has no lwl instruction */
2015-03-09 17:54:50 +03:00
# define _LoadW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2014-10-28 13:42:23 +03:00
__asm__ __volatile__ ( \
" .set \t push \n " \
" .set \t noat \n \t " \
2015-03-09 17:54:50 +03:00
" 1: " type # # _lb ( " %0 " , " 0(%2) " ) " \n \t " \
" 2: " type # # _lbu ( " $1 " , " 1(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
2015-03-09 17:54:50 +03:00
" 3: " type # # _lbu ( " $1 " , " 2(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
2015-03-09 17:54:50 +03:00
" 4: " type # # _lbu ( " $1 " , " 3(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" li \t %1, 0 \n " \
" .set \t pop \n " \
" 10: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 11: \t li \t %1, %3 \n \t " \
" j \t 10b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 11b \n \t " \
STR ( PTR ) " \t 2b, 11b \n \t " \
STR ( PTR ) " \t 3b, 11b \n \t " \
STR ( PTR ) " \t 4b, 11b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# endif /* CONFIG_CPU_MIPSR6 */
2013-03-25 22:18:07 +04:00
2015-03-09 17:54:50 +03:00
# define _LoadHWU(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
" .set \t noat \n " \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _lbu ( " %0 " , " 0(%2) " ) " \n " \
" 2: \t " type # # _lbu ( " $1 " , " 1(%2) " ) " \n \t " \
2013-03-25 22:18:07 +04:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" li \t %1, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" .set \t at \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %1, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2013-03-25 22:18:07 +04:00
2014-10-28 13:42:23 +03:00
# ifndef CONFIG_CPU_MIPSR6
2015-03-09 17:54:50 +03:00
# define _LoadWU(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _lwl ( " %0 " , " (%2) " ) " \n " \
" 2: \t " type # # _lwr ( " %0 " , " 3(%2) " ) " \n \t " \
2013-03-25 22:18:07 +04:00
" dsll \t %0, %0, 32 \n \t " \
" dsrl \t %0, %0, 32 \n \t " \
" li \t %1, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" \t .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %1, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2013-03-25 22:18:07 +04:00
2015-03-09 17:54:50 +03:00
# define _LoadDW(addr, value, res) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
" 1: \t ldl \t %0, (%2) \n " \
" 2: \t ldr \t %0, 7(%2) \n \t " \
" li \t %1, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" \t .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %1, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# else
/* MIPSR6 has not lwl and ldl instructions */
2015-03-09 17:54:50 +03:00
# define _LoadWU(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2014-10-28 13:42:23 +03:00
__asm__ __volatile__ ( \
" .set \t push \n \t " \
" .set \t noat \n \t " \
2015-03-09 17:54:50 +03:00
" 1: " type # # _lbu ( " %0 " , " 0(%2) " ) " \n \t " \
" 2: " type # # _lbu ( " $1 " , " 1(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
2015-03-09 17:54:50 +03:00
" 3: " type # # _lbu ( " $1 " , " 2(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
2015-03-09 17:54:50 +03:00
" 4: " type # # _lbu ( " $1 " , " 3(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" li \t %1, 0 \n " \
" .set \t pop \n " \
" 10: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 11: \t li \t %1, %3 \n \t " \
" j \t 10b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 11b \n \t " \
STR ( PTR ) " \t 2b, 11b \n \t " \
STR ( PTR ) " \t 3b, 11b \n \t " \
STR ( PTR ) " \t 4b, 11b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
2015-03-09 17:54:50 +03:00
# define _LoadDW(addr, value, res) \
2015-03-09 17:54:51 +03:00
do { \
2014-10-28 13:42:23 +03:00
__asm__ __volatile__ ( \
" .set \t push \n \t " \
" .set \t noat \n \t " \
" 1:lb \t %0, 0(%2) \n \t " \
" 2:lbu \t $1, 1(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 3:lbu \t $1, 2(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 4:lbu \t $1, 3(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 5:lbu \t $1, 4(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 6:lbu \t $1, 5(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 7:lbu \t $1, 6(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 8:lbu \t $1, 7(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" li \t %1, 0 \n " \
" .set \t pop \n \t " \
" 10: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 11: \t li \t %1, %3 \n \t " \
" j \t 10b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 11b \n \t " \
STR ( PTR ) " \t 2b, 11b \n \t " \
STR ( PTR ) " \t 3b, 11b \n \t " \
STR ( PTR ) " \t 4b, 11b \n \t " \
STR ( PTR ) " \t 5b, 11b \n \t " \
STR ( PTR ) " \t 6b, 11b \n \t " \
STR ( PTR ) " \t 7b, 11b \n \t " \
STR ( PTR ) " \t 8b, 11b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# endif /* CONFIG_CPU_MIPSR6 */
2013-03-25 22:18:07 +04:00
2015-03-09 17:54:50 +03:00
# define _StoreHW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
" .set \t noat \n " \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _sb ( " %1 " , " 1(%2) " ) " \n " \
2013-03-25 22:18:07 +04:00
" srl \t $1, %1, 0x8 \n " \
2015-03-09 17:54:50 +03:00
" 2: \t " type # # _sb ( " $1 " , " 0(%2) " ) " \n " \
2013-03-25 22:18:07 +04:00
" .set \t at \n \t " \
" li \t %0, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %0, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( value ) , " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2013-03-25 22:18:07 +04:00
2014-10-28 13:42:23 +03:00
# ifndef CONFIG_CPU_MIPSR6
2015-03-09 17:54:50 +03:00
# define _StoreW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _swl ( " %1 " , " (%2) " ) " \n " \
" 2: \t " type # # _swr ( " %1 " , " 3(%2) " ) " \n \t " \
2013-03-25 22:18:07 +04:00
" li \t %0, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %0, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( value ) , " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2013-03-25 22:18:07 +04:00
2015-03-09 17:54:50 +03:00
# define _StoreDW(addr, value, res) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
" 1: \t sdl \t %1,(%2) \n " \
" 2: \t sdr \t %1, 7(%2) \n \t " \
" li \t %0, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %0, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( value ) , " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# else
/* MIPSR6 has no swl and sdl instructions */
2015-03-09 17:54:50 +03:00
# define _StoreW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2014-10-28 13:42:23 +03:00
__asm__ __volatile__ ( \
" .set \t push \n \t " \
" .set \t noat \n \t " \
2015-03-09 17:54:50 +03:00
" 1: " type # # _sb ( " %1 " , " 3(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" srl \t $1, %1, 0x8 \n \t " \
2015-03-09 17:54:50 +03:00
" 2: " type # # _sb ( " $1 " , " 2(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" srl \t $1, $1, 0x8 \n \t " \
2015-03-09 17:54:50 +03:00
" 3: " type # # _sb ( " $1 " , " 1(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" srl \t $1, $1, 0x8 \n \t " \
2015-03-09 17:54:50 +03:00
" 4: " type # # _sb ( " $1 " , " 0(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" .set \t pop \n \t " \
" li \t %0, 0 \n " \
" 10: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 11: \t li \t %0, %3 \n \t " \
" j \t 10b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 11b \n \t " \
STR ( PTR ) " \t 2b, 11b \n \t " \
STR ( PTR ) " \t 3b, 11b \n \t " \
STR ( PTR ) " \t 4b, 11b \n \t " \
" .previous " \
: " =&r " ( res ) \
: " r " ( value ) , " r " ( addr ) , " i " ( - EFAULT ) \
2015-03-09 17:54:51 +03:00
: " memory " ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# define StoreDW(addr, value, res) \
2015-03-09 17:54:51 +03:00
do { \
2014-10-28 13:42:23 +03:00
__asm__ __volatile__ ( \
" .set \t push \n \t " \
" .set \t noat \n \t " \
" 1:sb \t %1, 7(%2) \n \t " \
" dsrl \t $1, %1, 0x8 \n \t " \
" 2:sb \t $1, 6(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 3:sb \t $1, 5(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 4:sb \t $1, 4(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 5:sb \t $1, 3(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 6:sb \t $1, 2(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 7:sb \t $1, 1(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 8:sb \t $1, 0(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" .set \t pop \n \t " \
" li \t %0, 0 \n " \
" 10: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 11: \t li \t %0, %3 \n \t " \
" j \t 10b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 11b \n \t " \
STR ( PTR ) " \t 2b, 11b \n \t " \
STR ( PTR ) " \t 3b, 11b \n \t " \
STR ( PTR ) " \t 4b, 11b \n \t " \
STR ( PTR ) " \t 5b, 11b \n \t " \
STR ( PTR ) " \t 6b, 11b \n \t " \
STR ( PTR ) " \t 7b, 11b \n \t " \
STR ( PTR ) " \t 8b, 11b \n \t " \
" .previous " \
: " =&r " ( res ) \
: " r " ( value ) , " r " ( addr ) , " i " ( - EFAULT ) \
2015-03-09 17:54:51 +03:00
: " memory " ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# endif /* CONFIG_CPU_MIPSR6 */
# else /* __BIG_ENDIAN */
2013-03-25 22:18:07 +04:00
2015-03-09 17:54:50 +03:00
# define _LoadHW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( " .set \t noat \n " \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _lb ( " %0 " , " 1(%2) " ) " \n " \
" 2: \t " type # # _lbu ( " $1 " , " 0(%2) " ) " \n \t " \
2013-03-25 22:18:07 +04:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" li \t %1, 0 \n " \
" 3: \t .set \t at \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %1, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2013-03-25 22:18:07 +04:00
2014-10-28 13:42:23 +03:00
# ifndef CONFIG_CPU_MIPSR6
2015-03-09 17:54:50 +03:00
# define _LoadW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _lwl ( " %0 " , " 3(%2) " ) " \n " \
" 2: \t " type # # _lwr ( " %0 " , " (%2) " ) " \n \t " \
2013-03-25 22:18:07 +04:00
" li \t %1, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %1, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# else
/* MIPSR6 has no lwl instruction */
2015-03-09 17:54:50 +03:00
# define _LoadW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2014-10-28 13:42:23 +03:00
__asm__ __volatile__ ( \
" .set \t push \n " \
" .set \t noat \n \t " \
2015-03-09 17:54:50 +03:00
" 1: " type # # _lb ( " %0 " , " 3(%2) " ) " \n \t " \
" 2: " type # # _lbu ( " $1 " , " 2(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
2015-03-09 17:54:50 +03:00
" 3: " type # # _lbu ( " $1 " , " 1(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
2015-03-09 17:54:50 +03:00
" 4: " type # # _lbu ( " $1 " , " 0(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" li \t %1, 0 \n " \
" .set \t pop \n " \
" 10: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 11: \t li \t %1, %3 \n \t " \
" j \t 10b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 11b \n \t " \
STR ( PTR ) " \t 2b, 11b \n \t " \
STR ( PTR ) " \t 3b, 11b \n \t " \
STR ( PTR ) " \t 4b, 11b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# endif /* CONFIG_CPU_MIPSR6 */
2013-03-25 22:18:07 +04:00
2015-03-09 17:54:50 +03:00
# define _LoadHWU(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
" .set \t noat \n " \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _lbu ( " %0 " , " 1(%2) " ) " \n " \
" 2: \t " type # # _lbu ( " $1 " , " 0(%2) " ) " \n \t " \
2013-03-25 22:18:07 +04:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" li \t %1, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" .set \t at \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %1, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2013-03-25 22:18:07 +04:00
2014-10-28 13:42:23 +03:00
# ifndef CONFIG_CPU_MIPSR6
2015-03-09 17:54:50 +03:00
# define _LoadWU(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _lwl ( " %0 " , " 3(%2) " ) " \n " \
" 2: \t " type # # _lwr ( " %0 " , " (%2) " ) " \n \t " \
2013-03-25 22:18:07 +04:00
" dsll \t %0, %0, 32 \n \t " \
" dsrl \t %0, %0, 32 \n \t " \
" li \t %1, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" \t .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %1, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2013-03-25 22:18:07 +04:00
2015-03-09 17:54:50 +03:00
# define _LoadDW(addr, value, res) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
" 1: \t ldl \t %0, 7(%2) \n " \
" 2: \t ldr \t %0, (%2) \n \t " \
" li \t %1, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" \t .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %1, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# else
/* MIPSR6 has not lwl and ldl instructions */
2015-03-09 17:54:50 +03:00
# define _LoadWU(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2014-10-28 13:42:23 +03:00
__asm__ __volatile__ ( \
" .set \t push \n \t " \
" .set \t noat \n \t " \
2015-03-09 17:54:50 +03:00
" 1: " type # # _lbu ( " %0 " , " 3(%2) " ) " \n \t " \
" 2: " type # # _lbu ( " $1 " , " 2(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
2015-03-09 17:54:50 +03:00
" 3: " type # # _lbu ( " $1 " , " 1(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
2015-03-09 17:54:50 +03:00
" 4: " type # # _lbu ( " $1 " , " 0(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" sll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" li \t %1, 0 \n " \
" .set \t pop \n " \
" 10: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 11: \t li \t %1, %3 \n \t " \
" j \t 10b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 11b \n \t " \
STR ( PTR ) " \t 2b, 11b \n \t " \
STR ( PTR ) " \t 3b, 11b \n \t " \
STR ( PTR ) " \t 4b, 11b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
2015-03-09 17:54:50 +03:00
# define _LoadDW(addr, value, res) \
2015-03-09 17:54:51 +03:00
do { \
2014-10-28 13:42:23 +03:00
__asm__ __volatile__ ( \
" .set \t push \n \t " \
" .set \t noat \n \t " \
" 1:lb \t %0, 7(%2) \n \t " \
" 2:lbu \t $1, 6(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 3:lbu \t $1, 5(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 4:lbu \t $1, 4(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 5:lbu \t $1, 3(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 6:lbu \t $1, 2(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 7:lbu \t $1, 1(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" 8:lbu \t $1, 0(%2) \n \t " \
" dsll \t %0, 0x8 \n \t " \
" or \t %0, $1 \n \t " \
" li \t %1, 0 \n " \
" .set \t pop \n \t " \
" 10: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 11: \t li \t %1, %3 \n \t " \
" j \t 10b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 11b \n \t " \
STR ( PTR ) " \t 2b, 11b \n \t " \
STR ( PTR ) " \t 3b, 11b \n \t " \
STR ( PTR ) " \t 4b, 11b \n \t " \
STR ( PTR ) " \t 5b, 11b \n \t " \
STR ( PTR ) " \t 6b, 11b \n \t " \
STR ( PTR ) " \t 7b, 11b \n \t " \
STR ( PTR ) " \t 8b, 11b \n \t " \
" .previous " \
: " =&r " ( value ) , " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# endif /* CONFIG_CPU_MIPSR6 */
2013-03-25 22:18:07 +04:00
2015-03-09 17:54:50 +03:00
# define _StoreHW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
" .set \t noat \n " \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _sb ( " %1 " , " 0(%2) " ) " \n " \
2013-03-25 22:18:07 +04:00
" srl \t $1,%1, 0x8 \n " \
2015-03-09 17:54:50 +03:00
" 2: \t " type # # _sb ( " $1 " , " 1(%2) " ) " \n " \
2013-03-25 22:18:07 +04:00
" .set \t at \n \t " \
" li \t %0, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %0, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( value ) , " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# ifndef CONFIG_CPU_MIPSR6
2015-03-09 17:54:50 +03:00
# define _StoreW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
2015-03-09 17:54:50 +03:00
" 1: \t " type # # _swl ( " %1 " , " 3(%2) " ) " \n " \
" 2: \t " type # # _swr ( " %1 " , " (%2) " ) " \n \t " \
2013-03-25 22:18:07 +04:00
" li \t %0, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %0, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( value ) , " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2013-03-25 22:18:07 +04:00
2015-03-09 17:54:50 +03:00
# define _StoreDW(addr, value, res) \
2015-03-09 17:54:51 +03:00
do { \
2013-03-25 22:18:07 +04:00
__asm__ __volatile__ ( \
" 1: \t sdl \t %1, 7(%2) \n " \
" 2: \t sdr \t %1, (%2) \n \t " \
" li \t %0, 0 \n " \
" 3: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 4: \t li \t %0, %3 \n \t " \
" j \t 3b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 4b \n \t " \
STR ( PTR ) " \t 2b, 4b \n \t " \
" .previous " \
: " =r " ( res ) \
2015-03-09 17:54:51 +03:00
: " r " ( value ) , " r " ( addr ) , " i " ( - EFAULT ) ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# else
/* MIPSR6 has no swl and sdl instructions */
2015-03-09 17:54:50 +03:00
# define _StoreW(addr, value, res, type) \
2015-03-09 17:54:51 +03:00
do { \
2014-10-28 13:42:23 +03:00
__asm__ __volatile__ ( \
" .set \t push \n \t " \
" .set \t noat \n \t " \
2015-03-09 17:54:50 +03:00
" 1: " type # # _sb ( " %1 " , " 0(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" srl \t $1, %1, 0x8 \n \t " \
2015-03-09 17:54:50 +03:00
" 2: " type # # _sb ( " $1 " , " 1(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" srl \t $1, $1, 0x8 \n \t " \
2015-03-09 17:54:50 +03:00
" 3: " type # # _sb ( " $1 " , " 2(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" srl \t $1, $1, 0x8 \n \t " \
2015-03-09 17:54:50 +03:00
" 4: " type # # _sb ( " $1 " , " 3(%2) " ) " \n \t " \
2014-10-28 13:42:23 +03:00
" .set \t pop \n \t " \
" li \t %0, 0 \n " \
" 10: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 11: \t li \t %0, %3 \n \t " \
" j \t 10b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 11b \n \t " \
STR ( PTR ) " \t 2b, 11b \n \t " \
STR ( PTR ) " \t 3b, 11b \n \t " \
STR ( PTR ) " \t 4b, 11b \n \t " \
" .previous " \
: " =&r " ( res ) \
: " r " ( value ) , " r " ( addr ) , " i " ( - EFAULT ) \
2015-03-09 17:54:51 +03:00
: " memory " ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
2015-03-09 17:54:50 +03:00
# define _StoreDW(addr, value, res) \
2015-03-09 17:54:51 +03:00
do { \
2014-10-28 13:42:23 +03:00
__asm__ __volatile__ ( \
" .set \t push \n \t " \
" .set \t noat \n \t " \
" 1:sb \t %1, 0(%2) \n \t " \
" dsrl \t $1, %1, 0x8 \n \t " \
" 2:sb \t $1, 1(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 3:sb \t $1, 2(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 4:sb \t $1, 3(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 5:sb \t $1, 4(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 6:sb \t $1, 5(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 7:sb \t $1, 6(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" 8:sb \t $1, 7(%2) \n \t " \
" dsrl \t $1, $1, 0x8 \n \t " \
" .set \t pop \n \t " \
" li \t %0, 0 \n " \
" 10: \n \t " \
" .insn \n \t " \
" .section \t .fixup, \" ax \" \n \t " \
" 11: \t li \t %0, %3 \n \t " \
" j \t 10b \n \t " \
" .previous \n \t " \
" .section \t __ex_table, \" a \" \n \t " \
STR ( PTR ) " \t 1b, 11b \n \t " \
STR ( PTR ) " \t 2b, 11b \n \t " \
STR ( PTR ) " \t 3b, 11b \n \t " \
STR ( PTR ) " \t 4b, 11b \n \t " \
STR ( PTR ) " \t 5b, 11b \n \t " \
STR ( PTR ) " \t 6b, 11b \n \t " \
STR ( PTR ) " \t 7b, 11b \n \t " \
STR ( PTR ) " \t 8b, 11b \n \t " \
" .previous " \
: " =&r " ( res ) \
: " r " ( value ) , " r " ( addr ) , " i " ( - EFAULT ) \
2015-03-09 17:54:51 +03:00
: " memory " ) ; \
} while ( 0 )
2014-10-28 13:42:23 +03:00
# endif /* CONFIG_CPU_MIPSR6 */
2013-03-25 22:18:07 +04:00
# endif
2015-03-09 17:54:50 +03:00
# define LoadHWU(addr, value, res) _LoadHWU(addr, value, res, kernel)
# define LoadHWUE(addr, value, res) _LoadHWU(addr, value, res, user)
# define LoadWU(addr, value, res) _LoadWU(addr, value, res, kernel)
# define LoadWUE(addr, value, res) _LoadWU(addr, value, res, user)
# define LoadHW(addr, value, res) _LoadHW(addr, value, res, kernel)
# define LoadHWE(addr, value, res) _LoadHW(addr, value, res, user)
# define LoadW(addr, value, res) _LoadW(addr, value, res, kernel)
# define LoadWE(addr, value, res) _LoadW(addr, value, res, user)
# define LoadDW(addr, value, res) _LoadDW(addr, value, res)
# define StoreHW(addr, value, res) _StoreHW(addr, value, res, kernel)
# define StoreHWE(addr, value, res) _StoreHW(addr, value, res, user)
# define StoreW(addr, value, res) _StoreW(addr, value, res, kernel)
# define StoreWE(addr, value, res) _StoreW(addr, value, res, user)
# define StoreDW(addr, value, res) _StoreDW(addr, value, res)
2007-07-29 12:16:19 +04:00
static void emulate_load_store_insn ( struct pt_regs * regs ,
void __user * addr , unsigned int __user * pc )
2005-04-17 02:20:36 +04:00
{
union mips_instruction insn ;
unsigned long value ;
unsigned int res ;
2013-03-25 22:18:07 +04:00
unsigned long origpc ;
unsigned long orig31 ;
2013-03-25 21:09:02 +04:00
void __user * fault_addr = NULL ;
2013-12-12 20:15:15 +04:00
# ifdef CONFIG_EVA
mm_segment_t seg ;
# endif
2013-03-25 22:18:07 +04:00
origpc = ( unsigned long ) pc ;
orig31 = regs - > regs [ 31 ] ;
2011-06-27 16:41:57 +04:00
perf_sw_event ( PERF_COUNT_SW_EMULATION_FAULTS , 1 , regs , 0 ) ;
2010-10-12 15:37:21 +04:00
2005-04-17 02:20:36 +04:00
/*
* This load never faults .
*/
2005-03-01 22:22:29 +03:00
__get_user ( insn . word , pc ) ;
2005-04-17 02:20:36 +04:00
switch ( insn . i_format . opcode ) {
2013-03-25 22:18:07 +04:00
/*
* These are instructions that a compiler doesn ' t generate . We
* can assume therefore that the code is MIPS - aware and
* really buggy . Emulating these instructions would break the
* semantics anyway .
*/
2005-04-17 02:20:36 +04:00
case ll_op :
case lld_op :
case sc_op :
case scd_op :
2013-03-25 22:18:07 +04:00
/*
* For these instructions the only way to create an address
* error is an attempted access to kernel / supervisor address
* space .
*/
2005-04-17 02:20:36 +04:00
case ldl_op :
case ldr_op :
case lwl_op :
case lwr_op :
case sdl_op :
case sdr_op :
case swl_op :
case swr_op :
case lb_op :
case lbu_op :
case sb_op :
goto sigbus ;
2013-03-25 22:18:07 +04:00
/*
* The remaining opcodes are the ones that are really of
* interest .
*/
2013-12-12 20:15:15 +04:00
# ifdef CONFIG_EVA
case spec3_op :
/*
* we can land here only from kernel accessing user memory ,
* so we need to " switch " the address limit to user space , so
* address check can work properly .
*/
seg = get_fs ( ) ;
set_fs ( USER_DS ) ;
switch ( insn . spec3_format . func ) {
case lhe_op :
if ( ! access_ok ( VERIFY_READ , addr , 2 ) ) {
set_fs ( seg ) ;
goto sigbus ;
}
2015-03-09 17:54:50 +03:00
LoadHWE ( addr , value , res ) ;
2013-12-12 20:15:15 +04:00
if ( res ) {
set_fs ( seg ) ;
goto fault ;
}
compute_return_epc ( regs ) ;
regs - > regs [ insn . spec3_format . rt ] = value ;
break ;
case lwe_op :
if ( ! access_ok ( VERIFY_READ , addr , 4 ) ) {
set_fs ( seg ) ;
goto sigbus ;
}
2015-03-09 17:54:50 +03:00
LoadWE ( addr , value , res ) ;
2013-12-12 20:15:15 +04:00
if ( res ) {
set_fs ( seg ) ;
goto fault ;
}
compute_return_epc ( regs ) ;
regs - > regs [ insn . spec3_format . rt ] = value ;
break ;
case lhue_op :
if ( ! access_ok ( VERIFY_READ , addr , 2 ) ) {
set_fs ( seg ) ;
goto sigbus ;
}
2015-03-09 17:54:50 +03:00
LoadHWUE ( addr , value , res ) ;
2013-12-12 20:15:15 +04:00
if ( res ) {
set_fs ( seg ) ;
goto fault ;
}
compute_return_epc ( regs ) ;
regs - > regs [ insn . spec3_format . rt ] = value ;
break ;
case she_op :
if ( ! access_ok ( VERIFY_WRITE , addr , 2 ) ) {
set_fs ( seg ) ;
goto sigbus ;
}
compute_return_epc ( regs ) ;
value = regs - > regs [ insn . spec3_format . rt ] ;
2015-03-09 17:54:50 +03:00
StoreHWE ( addr , value , res ) ;
2013-12-12 20:15:15 +04:00
if ( res ) {
set_fs ( seg ) ;
goto fault ;
}
break ;
case swe_op :
if ( ! access_ok ( VERIFY_WRITE , addr , 4 ) ) {
set_fs ( seg ) ;
goto sigbus ;
}
compute_return_epc ( regs ) ;
value = regs - > regs [ insn . spec3_format . rt ] ;
2015-03-09 17:54:50 +03:00
StoreWE ( addr , value , res ) ;
2013-12-12 20:15:15 +04:00
if ( res ) {
set_fs ( seg ) ;
goto fault ;
}
break ;
default :
set_fs ( seg ) ;
goto sigill ;
}
set_fs ( seg ) ;
break ;
# endif
2005-04-17 02:20:36 +04:00
case lh_op :
if ( ! access_ok ( VERIFY_READ , addr , 2 ) )
goto sigbus ;
2015-03-09 17:54:52 +03:00
if ( config_enabled ( CONFIG_EVA ) ) {
if ( segment_eq ( get_fs ( ) , get_ds ( ) ) )
LoadHW ( addr , value , res ) ;
else
LoadHWE ( addr , value , res ) ;
} else {
LoadHW ( addr , value , res ) ;
}
2005-04-17 02:20:36 +04:00
if ( res )
goto fault ;
2007-07-29 12:16:19 +04:00
compute_return_epc ( regs ) ;
regs - > regs [ insn . i_format . rt ] = value ;
2005-04-17 02:20:36 +04:00
break ;
case lw_op :
if ( ! access_ok ( VERIFY_READ , addr , 4 ) )
goto sigbus ;
2015-03-09 17:54:52 +03:00
if ( config_enabled ( CONFIG_EVA ) ) {
if ( segment_eq ( get_fs ( ) , get_ds ( ) ) )
LoadW ( addr , value , res ) ;
else
LoadWE ( addr , value , res ) ;
} else {
LoadW ( addr , value , res ) ;
}
2005-04-17 02:20:36 +04:00
if ( res )
goto fault ;
2007-07-29 12:16:19 +04:00
compute_return_epc ( regs ) ;
regs - > regs [ insn . i_format . rt ] = value ;
2005-04-17 02:20:36 +04:00
break ;
case lhu_op :
if ( ! access_ok ( VERIFY_READ , addr , 2 ) )
goto sigbus ;
2015-03-09 17:54:52 +03:00
if ( config_enabled ( CONFIG_EVA ) ) {
if ( segment_eq ( get_fs ( ) , get_ds ( ) ) )
LoadHWU ( addr , value , res ) ;
else
LoadHWUE ( addr , value , res ) ;
} else {
LoadHWU ( addr , value , res ) ;
}
2005-04-17 02:20:36 +04:00
if ( res )
goto fault ;
2007-07-29 12:16:19 +04:00
compute_return_epc ( regs ) ;
regs - > regs [ insn . i_format . rt ] = value ;
2005-04-17 02:20:36 +04:00
break ;
case lwu_op :
2005-09-04 02:56:16 +04:00
# ifdef CONFIG_64BIT
2005-04-17 02:20:36 +04:00
/*
* A 32 - bit kernel might be running on a 64 - bit processor . But
* if we ' re on a 32 - bit processor and an i - cache incoherency
* or race makes us see a 64 - bit instruction here the sdl / sdr
* would blow up , so for now we don ' t handle unaligned 64 - bit
* instructions on 32 - bit kernels .
*/
if ( ! access_ok ( VERIFY_READ , addr , 4 ) )
goto sigbus ;
2013-03-25 22:18:07 +04:00
LoadWU ( addr , value , res ) ;
2005-04-17 02:20:36 +04:00
if ( res )
goto fault ;
2007-07-29 12:16:19 +04:00
compute_return_epc ( regs ) ;
regs - > regs [ insn . i_format . rt ] = value ;
2005-04-17 02:20:36 +04:00
break ;
2005-09-04 02:56:16 +04:00
# endif /* CONFIG_64BIT */
2005-04-17 02:20:36 +04:00
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill ;
case ld_op :
2005-09-04 02:56:16 +04:00
# ifdef CONFIG_64BIT
2005-04-17 02:20:36 +04:00
/*
* A 32 - bit kernel might be running on a 64 - bit processor . But
* if we ' re on a 32 - bit processor and an i - cache incoherency
* or race makes us see a 64 - bit instruction here the sdl / sdr
* would blow up , so for now we don ' t handle unaligned 64 - bit
* instructions on 32 - bit kernels .
*/
if ( ! access_ok ( VERIFY_READ , addr , 8 ) )
goto sigbus ;
2013-03-25 22:18:07 +04:00
LoadDW ( addr , value , res ) ;
2005-04-17 02:20:36 +04:00
if ( res )
goto fault ;
2007-07-29 12:16:19 +04:00
compute_return_epc ( regs ) ;
regs - > regs [ insn . i_format . rt ] = value ;
2005-04-17 02:20:36 +04:00
break ;
2005-09-04 02:56:16 +04:00
# endif /* CONFIG_64BIT */
2005-04-17 02:20:36 +04:00
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill ;
case sh_op :
if ( ! access_ok ( VERIFY_WRITE , addr , 2 ) )
goto sigbus ;
2013-03-25 22:18:07 +04:00
compute_return_epc ( regs ) ;
2005-04-17 02:20:36 +04:00
value = regs - > regs [ insn . i_format . rt ] ;
2015-03-09 17:54:52 +03:00
if ( config_enabled ( CONFIG_EVA ) ) {
if ( segment_eq ( get_fs ( ) , get_ds ( ) ) )
StoreHW ( addr , value , res ) ;
else
StoreHWE ( addr , value , res ) ;
} else {
StoreHW ( addr , value , res ) ;
}
2005-04-17 02:20:36 +04:00
if ( res )
goto fault ;
break ;
case sw_op :
if ( ! access_ok ( VERIFY_WRITE , addr , 4 ) )
goto sigbus ;
2013-03-25 22:18:07 +04:00
compute_return_epc ( regs ) ;
2005-04-17 02:20:36 +04:00
value = regs - > regs [ insn . i_format . rt ] ;
2015-03-09 17:54:52 +03:00
if ( config_enabled ( CONFIG_EVA ) ) {
if ( segment_eq ( get_fs ( ) , get_ds ( ) ) )
StoreW ( addr , value , res ) ;
else
StoreWE ( addr , value , res ) ;
} else {
StoreW ( addr , value , res ) ;
}
2005-04-17 02:20:36 +04:00
if ( res )
goto fault ;
break ;
case sd_op :
2005-09-04 02:56:16 +04:00
# ifdef CONFIG_64BIT
2005-04-17 02:20:36 +04:00
/*
* A 32 - bit kernel might be running on a 64 - bit processor . But
* if we ' re on a 32 - bit processor and an i - cache incoherency
* or race makes us see a 64 - bit instruction here the sdl / sdr
* would blow up , so for now we don ' t handle unaligned 64 - bit
* instructions on 32 - bit kernels .
*/
if ( ! access_ok ( VERIFY_WRITE , addr , 8 ) )
goto sigbus ;
2013-03-25 22:18:07 +04:00
compute_return_epc ( regs ) ;
2005-04-17 02:20:36 +04:00
value = regs - > regs [ insn . i_format . rt ] ;
2013-03-25 22:18:07 +04:00
StoreDW ( addr , value , res ) ;
2005-04-17 02:20:36 +04:00
if ( res )
goto fault ;
break ;
2005-09-04 02:56:16 +04:00
# endif /* CONFIG_64BIT */
2005-04-17 02:20:36 +04:00
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill ;
case lwc1_op :
case ldc1_op :
case swc1_op :
case sdc1_op :
2013-03-25 21:09:02 +04:00
die_if_kernel ( " Unaligned FP access in kernel code " , regs ) ;
BUG_ON ( ! used_math ( ) ) ;
lose_fpu ( 1 ) ; /* Save FPU state for the emulator. */
res = fpu_emulator_cop1Handler ( regs , & current - > thread . fpu , 1 ,
& fault_addr ) ;
own_fpu ( 1 ) ; /* Restore FPU state. */
/* Signal if something went wrong. */
2015-04-04 01:27:15 +03:00
process_fpemu_return ( res , fault_addr , 0 ) ;
2013-03-25 21:09:02 +04:00
if ( res = = 0 )
break ;
return ;
2005-04-17 02:20:36 +04:00
2014-10-28 13:42:23 +03:00
# ifndef CONFIG_CPU_MIPSR6
2009-11-24 04:24:58 +03:00
/*
* COP2 is available to implementor for application specific use .
* It ' s up to applications to register a notifier chain and do
* whatever they have to do , including possible sending of signals .
2014-10-28 13:42:23 +03:00
*
* This instruction has been reallocated in Release 6
2009-11-24 04:24:58 +03:00
*/
2005-04-17 02:20:36 +04:00
case lwc2_op :
2009-11-24 04:24:58 +03:00
cu2_notifier_call_chain ( CU2_LWC2_OP , regs ) ;
break ;
2005-04-17 02:20:36 +04:00
case ldc2_op :
2009-11-24 04:24:58 +03:00
cu2_notifier_call_chain ( CU2_LDC2_OP , regs ) ;
break ;
2005-04-17 02:20:36 +04:00
case swc2_op :
2009-11-24 04:24:58 +03:00
cu2_notifier_call_chain ( CU2_SWC2_OP , regs ) ;
break ;
2005-04-17 02:20:36 +04:00
case sdc2_op :
2009-11-24 04:24:58 +03:00
cu2_notifier_call_chain ( CU2_SDC2_OP , regs ) ;
break ;
2014-10-28 13:42:23 +03:00
# endif
2005-04-17 02:20:36 +04:00
default :
/*
* Pheeee . . . We encountered an yet unknown instruction or
* cache coherence problem . Die sucker , die . . .
*/
goto sigill ;
}
2007-06-29 19:55:48 +04:00
# ifdef CONFIG_DEBUG_FS
2005-04-17 02:20:36 +04:00
unaligned_instructions + + ;
# endif
2007-07-29 12:16:19 +04:00
return ;
2005-04-17 02:20:36 +04:00
fault :
2013-03-25 22:18:07 +04:00
/* roll back jump/branch */
regs - > cp0_epc = origpc ;
regs - > regs [ 31 ] = orig31 ;
/* Did we have an exception handler installed? */
if ( fixup_exception ( regs ) )
return ;
die_if_kernel ( " Unhandled kernel unaligned access " , regs ) ;
force_sig ( SIGSEGV , current ) ;
return ;
sigbus :
die_if_kernel ( " Unhandled kernel unaligned access " , regs ) ;
force_sig ( SIGBUS , current ) ;
return ;
sigill :
die_if_kernel
( " Unhandled kernel unaligned access or invalid instruction " , regs ) ;
force_sig ( SIGILL , current ) ;
}
/* Recode table from 16-bit register notation to 32-bit GPR. */
const int reg16to32 [ ] = { 16 , 17 , 2 , 3 , 4 , 5 , 6 , 7 } ;
/* Recode table from 16-bit STORE register notation to 32-bit GPR. */
const int reg16to32st [ ] = { 0 , 17 , 2 , 3 , 4 , 5 , 6 , 7 } ;
2013-05-25 00:54:08 +04:00
static void emulate_load_store_microMIPS ( struct pt_regs * regs ,
void __user * addr )
2013-03-25 22:18:07 +04:00
{
unsigned long value ;
unsigned int res ;
int i ;
unsigned int reg = 0 , rvar ;
unsigned long orig31 ;
u16 __user * pc16 ;
u16 halfword ;
unsigned int word ;
unsigned long origpc , contpc ;
union mips_instruction insn ;
struct mm_decoded_insn mminsn ;
void __user * fault_addr = NULL ;
origpc = regs - > cp0_epc ;
orig31 = regs - > regs [ 31 ] ;
mminsn . micro_mips_mode = 1 ;
/*
* This load never faults .
*/
pc16 = ( unsigned short __user * ) msk_isa16_mode ( regs - > cp0_epc ) ;
__get_user ( halfword , pc16 ) ;
pc16 + + ;
contpc = regs - > cp0_epc + 2 ;
word = ( ( unsigned int ) halfword < < 16 ) ;
mminsn . pc_inc = 2 ;
if ( ! mm_insn_16bit ( halfword ) ) {
__get_user ( halfword , pc16 ) ;
pc16 + + ;
contpc = regs - > cp0_epc + 4 ;
mminsn . pc_inc = 4 ;
word | = halfword ;
}
mminsn . insn = word ;
if ( get_user ( halfword , pc16 ) )
goto fault ;
mminsn . next_pc_inc = 2 ;
word = ( ( unsigned int ) halfword < < 16 ) ;
if ( ! mm_insn_16bit ( halfword ) ) {
pc16 + + ;
if ( get_user ( halfword , pc16 ) )
goto fault ;
mminsn . next_pc_inc = 4 ;
word | = halfword ;
}
mminsn . next_insn = word ;
insn = ( union mips_instruction ) ( mminsn . insn ) ;
if ( mm_isBranchInstr ( regs , mminsn , & contpc ) )
insn = ( union mips_instruction ) ( mminsn . next_insn ) ;
/* Parse instruction to find what to do */
switch ( insn . mm_i_format . opcode ) {
case mm_pool32a_op :
switch ( insn . mm_x_format . func ) {
case mm_lwxs_op :
reg = insn . mm_x_format . rd ;
goto loadW ;
}
goto sigbus ;
case mm_pool32b_op :
switch ( insn . mm_m_format . func ) {
case mm_lwp_func :
reg = insn . mm_m_format . rd ;
if ( reg = = 31 )
goto sigbus ;
if ( ! access_ok ( VERIFY_READ , addr , 8 ) )
goto sigbus ;
LoadW ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ reg ] = value ;
addr + = 4 ;
LoadW ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ reg + 1 ] = value ;
goto success ;
case mm_swp_func :
reg = insn . mm_m_format . rd ;
if ( reg = = 31 )
goto sigbus ;
if ( ! access_ok ( VERIFY_WRITE , addr , 8 ) )
goto sigbus ;
value = regs - > regs [ reg ] ;
StoreW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 4 ;
value = regs - > regs [ reg + 1 ] ;
StoreW ( addr , value , res ) ;
if ( res )
goto fault ;
goto success ;
case mm_ldp_func :
# ifdef CONFIG_64BIT
reg = insn . mm_m_format . rd ;
if ( reg = = 31 )
goto sigbus ;
if ( ! access_ok ( VERIFY_READ , addr , 16 ) )
goto sigbus ;
LoadDW ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ reg ] = value ;
addr + = 8 ;
LoadDW ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ reg + 1 ] = value ;
goto success ;
# endif /* CONFIG_64BIT */
goto sigill ;
case mm_sdp_func :
# ifdef CONFIG_64BIT
reg = insn . mm_m_format . rd ;
if ( reg = = 31 )
goto sigbus ;
if ( ! access_ok ( VERIFY_WRITE , addr , 16 ) )
goto sigbus ;
value = regs - > regs [ reg ] ;
StoreDW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 8 ;
value = regs - > regs [ reg + 1 ] ;
StoreDW ( addr , value , res ) ;
if ( res )
goto fault ;
goto success ;
# endif /* CONFIG_64BIT */
goto sigill ;
case mm_lwm32_func :
reg = insn . mm_m_format . rd ;
rvar = reg & 0xf ;
if ( ( rvar > 9 ) | | ! reg )
goto sigill ;
if ( reg & 0x10 ) {
if ( ! access_ok
( VERIFY_READ , addr , 4 * ( rvar + 1 ) ) )
goto sigbus ;
} else {
if ( ! access_ok ( VERIFY_READ , addr , 4 * rvar ) )
goto sigbus ;
}
if ( rvar = = 9 )
rvar = 8 ;
for ( i = 16 ; rvar ; rvar - - , i + + ) {
LoadW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 4 ;
regs - > regs [ i ] = value ;
}
if ( ( reg & 0xf ) = = 9 ) {
LoadW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 4 ;
regs - > regs [ 30 ] = value ;
}
if ( reg & 0x10 ) {
LoadW ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ 31 ] = value ;
}
goto success ;
case mm_swm32_func :
reg = insn . mm_m_format . rd ;
rvar = reg & 0xf ;
if ( ( rvar > 9 ) | | ! reg )
goto sigill ;
if ( reg & 0x10 ) {
if ( ! access_ok
( VERIFY_WRITE , addr , 4 * ( rvar + 1 ) ) )
goto sigbus ;
} else {
if ( ! access_ok ( VERIFY_WRITE , addr , 4 * rvar ) )
goto sigbus ;
}
if ( rvar = = 9 )
rvar = 8 ;
for ( i = 16 ; rvar ; rvar - - , i + + ) {
value = regs - > regs [ i ] ;
StoreW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 4 ;
}
if ( ( reg & 0xf ) = = 9 ) {
value = regs - > regs [ 30 ] ;
StoreW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 4 ;
}
if ( reg & 0x10 ) {
value = regs - > regs [ 31 ] ;
StoreW ( addr , value , res ) ;
if ( res )
goto fault ;
}
goto success ;
case mm_ldm_func :
# ifdef CONFIG_64BIT
reg = insn . mm_m_format . rd ;
rvar = reg & 0xf ;
if ( ( rvar > 9 ) | | ! reg )
goto sigill ;
if ( reg & 0x10 ) {
if ( ! access_ok
( VERIFY_READ , addr , 8 * ( rvar + 1 ) ) )
goto sigbus ;
} else {
if ( ! access_ok ( VERIFY_READ , addr , 8 * rvar ) )
goto sigbus ;
}
if ( rvar = = 9 )
rvar = 8 ;
for ( i = 16 ; rvar ; rvar - - , i + + ) {
LoadDW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 4 ;
regs - > regs [ i ] = value ;
}
if ( ( reg & 0xf ) = = 9 ) {
LoadDW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 8 ;
regs - > regs [ 30 ] = value ;
}
if ( reg & 0x10 ) {
LoadDW ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ 31 ] = value ;
}
goto success ;
# endif /* CONFIG_64BIT */
goto sigill ;
case mm_sdm_func :
# ifdef CONFIG_64BIT
reg = insn . mm_m_format . rd ;
rvar = reg & 0xf ;
if ( ( rvar > 9 ) | | ! reg )
goto sigill ;
if ( reg & 0x10 ) {
if ( ! access_ok
( VERIFY_WRITE , addr , 8 * ( rvar + 1 ) ) )
goto sigbus ;
} else {
if ( ! access_ok ( VERIFY_WRITE , addr , 8 * rvar ) )
goto sigbus ;
}
if ( rvar = = 9 )
rvar = 8 ;
for ( i = 16 ; rvar ; rvar - - , i + + ) {
value = regs - > regs [ i ] ;
StoreDW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 8 ;
}
if ( ( reg & 0xf ) = = 9 ) {
value = regs - > regs [ 30 ] ;
StoreDW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 8 ;
}
if ( reg & 0x10 ) {
value = regs - > regs [ 31 ] ;
StoreDW ( addr , value , res ) ;
if ( res )
goto fault ;
}
goto success ;
# endif /* CONFIG_64BIT */
goto sigill ;
/* LWC2, SWC2, LDC2, SDC2 are not serviced */
}
goto sigbus ;
case mm_pool32c_op :
switch ( insn . mm_m_format . func ) {
case mm_lwu_func :
reg = insn . mm_m_format . rd ;
goto loadWU ;
}
/* LL,SC,LLD,SCD are not serviced */
goto sigbus ;
case mm_pool32f_op :
switch ( insn . mm_x_format . func ) {
case mm_lwxc1_func :
case mm_swxc1_func :
case mm_ldxc1_func :
case mm_sdxc1_func :
goto fpu_emul ;
}
goto sigbus ;
case mm_ldc132_op :
case mm_sdc132_op :
case mm_lwc132_op :
case mm_swc132_op :
fpu_emul :
/* roll back jump/branch */
regs - > cp0_epc = origpc ;
regs - > regs [ 31 ] = orig31 ;
die_if_kernel ( " Unaligned FP access in kernel code " , regs ) ;
BUG_ON ( ! used_math ( ) ) ;
BUG_ON ( ! is_fpu_owner ( ) ) ;
lose_fpu ( 1 ) ; /* save the FPU state for the emulator */
res = fpu_emulator_cop1Handler ( regs , & current - > thread . fpu , 1 ,
& fault_addr ) ;
own_fpu ( 1 ) ; /* restore FPU state */
/* If something went wrong, signal */
2015-04-04 01:27:15 +03:00
process_fpemu_return ( res , fault_addr , 0 ) ;
2013-03-25 22:18:07 +04:00
if ( res = = 0 )
goto success ;
return ;
case mm_lh32_op :
reg = insn . mm_i_format . rt ;
goto loadHW ;
case mm_lhu32_op :
reg = insn . mm_i_format . rt ;
goto loadHWU ;
case mm_lw32_op :
reg = insn . mm_i_format . rt ;
goto loadW ;
case mm_sh32_op :
reg = insn . mm_i_format . rt ;
goto storeHW ;
case mm_sw32_op :
reg = insn . mm_i_format . rt ;
goto storeW ;
case mm_ld32_op :
reg = insn . mm_i_format . rt ;
goto loadDW ;
case mm_sd32_op :
reg = insn . mm_i_format . rt ;
goto storeDW ;
case mm_pool16c_op :
switch ( insn . mm16_m_format . func ) {
case mm_lwm16_op :
reg = insn . mm16_m_format . rlist ;
rvar = reg + 1 ;
if ( ! access_ok ( VERIFY_READ , addr , 4 * rvar ) )
goto sigbus ;
for ( i = 16 ; rvar ; rvar - - , i + + ) {
LoadW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 4 ;
regs - > regs [ i ] = value ;
}
LoadW ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ 31 ] = value ;
goto success ;
case mm_swm16_op :
reg = insn . mm16_m_format . rlist ;
rvar = reg + 1 ;
if ( ! access_ok ( VERIFY_WRITE , addr , 4 * rvar ) )
goto sigbus ;
for ( i = 16 ; rvar ; rvar - - , i + + ) {
value = regs - > regs [ i ] ;
StoreW ( addr , value , res ) ;
if ( res )
goto fault ;
addr + = 4 ;
}
value = regs - > regs [ 31 ] ;
StoreW ( addr , value , res ) ;
if ( res )
goto fault ;
goto success ;
}
goto sigbus ;
case mm_lhu16_op :
reg = reg16to32 [ insn . mm16_rb_format . rt ] ;
goto loadHWU ;
case mm_lw16_op :
reg = reg16to32 [ insn . mm16_rb_format . rt ] ;
goto loadW ;
case mm_sh16_op :
reg = reg16to32st [ insn . mm16_rb_format . rt ] ;
goto storeHW ;
case mm_sw16_op :
reg = reg16to32st [ insn . mm16_rb_format . rt ] ;
goto storeW ;
case mm_lwsp16_op :
reg = insn . mm16_r5_format . rt ;
goto loadW ;
case mm_swsp16_op :
reg = insn . mm16_r5_format . rt ;
goto storeW ;
case mm_lwgp16_op :
reg = reg16to32 [ insn . mm16_r3_format . rt ] ;
goto loadW ;
default :
goto sigill ;
}
loadHW :
if ( ! access_ok ( VERIFY_READ , addr , 2 ) )
goto sigbus ;
LoadHW ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ reg ] = value ;
goto success ;
loadHWU :
if ( ! access_ok ( VERIFY_READ , addr , 2 ) )
goto sigbus ;
LoadHWU ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ reg ] = value ;
goto success ;
loadW :
if ( ! access_ok ( VERIFY_READ , addr , 4 ) )
goto sigbus ;
LoadW ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ reg ] = value ;
goto success ;
loadWU :
# ifdef CONFIG_64BIT
/*
* A 32 - bit kernel might be running on a 64 - bit processor . But
* if we ' re on a 32 - bit processor and an i - cache incoherency
* or race makes us see a 64 - bit instruction here the sdl / sdr
* would blow up , so for now we don ' t handle unaligned 64 - bit
* instructions on 32 - bit kernels .
*/
if ( ! access_ok ( VERIFY_READ , addr , 4 ) )
goto sigbus ;
LoadWU ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ reg ] = value ;
goto success ;
# endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill ;
loadDW :
# ifdef CONFIG_64BIT
/*
* A 32 - bit kernel might be running on a 64 - bit processor . But
* if we ' re on a 32 - bit processor and an i - cache incoherency
* or race makes us see a 64 - bit instruction here the sdl / sdr
* would blow up , so for now we don ' t handle unaligned 64 - bit
* instructions on 32 - bit kernels .
*/
if ( ! access_ok ( VERIFY_READ , addr , 8 ) )
goto sigbus ;
LoadDW ( addr , value , res ) ;
if ( res )
goto fault ;
regs - > regs [ reg ] = value ;
goto success ;
# endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill ;
storeHW :
if ( ! access_ok ( VERIFY_WRITE , addr , 2 ) )
goto sigbus ;
value = regs - > regs [ reg ] ;
StoreHW ( addr , value , res ) ;
if ( res )
goto fault ;
goto success ;
storeW :
if ( ! access_ok ( VERIFY_WRITE , addr , 4 ) )
goto sigbus ;
value = regs - > regs [ reg ] ;
StoreW ( addr , value , res ) ;
if ( res )
goto fault ;
goto success ;
storeDW :
# ifdef CONFIG_64BIT
/*
* A 32 - bit kernel might be running on a 64 - bit processor . But
* if we ' re on a 32 - bit processor and an i - cache incoherency
* or race makes us see a 64 - bit instruction here the sdl / sdr
* would blow up , so for now we don ' t handle unaligned 64 - bit
* instructions on 32 - bit kernels .
*/
if ( ! access_ok ( VERIFY_WRITE , addr , 8 ) )
goto sigbus ;
value = regs - > regs [ reg ] ;
StoreDW ( addr , value , res ) ;
if ( res )
goto fault ;
goto success ;
# endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill ;
success :
regs - > cp0_epc = contpc ; /* advance or branch */
# ifdef CONFIG_DEBUG_FS
unaligned_instructions + + ;
# endif
return ;
fault :
/* roll back jump/branch */
regs - > cp0_epc = origpc ;
regs - > regs [ 31 ] = orig31 ;
2005-04-17 02:20:36 +04:00
/* Did we have an exception handler installed? */
if ( fixup_exception ( regs ) )
2007-07-29 12:16:19 +04:00
return ;
2005-04-17 02:20:36 +04:00
2007-10-12 02:46:15 +04:00
die_if_kernel ( " Unhandled kernel unaligned access " , regs ) ;
2009-05-05 23:49:47 +04:00
force_sig ( SIGSEGV , current ) ;
2005-04-17 02:20:36 +04:00
2007-07-29 12:16:19 +04:00
return ;
2005-04-17 02:20:36 +04:00
sigbus :
die_if_kernel ( " Unhandled kernel unaligned access " , regs ) ;
2009-05-05 23:49:47 +04:00
force_sig ( SIGBUS , current ) ;
2005-04-17 02:20:36 +04:00
2007-07-29 12:16:19 +04:00
return ;
2005-04-17 02:20:36 +04:00
sigill :
2013-03-25 22:18:07 +04:00
die_if_kernel
( " Unhandled kernel unaligned access or invalid instruction " , regs ) ;
2009-05-05 23:49:47 +04:00
force_sig ( SIGILL , current ) ;
2005-04-17 02:20:36 +04:00
}
2013-03-25 22:46:15 +04:00
static void emulate_load_store_MIPS16e ( struct pt_regs * regs , void __user * addr )
{
unsigned long value ;
unsigned int res ;
int reg ;
unsigned long orig31 ;
u16 __user * pc16 ;
unsigned long origpc ;
union mips16e_instruction mips16inst , oldinst ;
origpc = regs - > cp0_epc ;
orig31 = regs - > regs [ 31 ] ;
pc16 = ( unsigned short __user * ) msk_isa16_mode ( origpc ) ;
/*
* This load never faults .
*/
__get_user ( mips16inst . full , pc16 ) ;
oldinst = mips16inst ;
/* skip EXTEND instruction */
if ( mips16inst . ri . opcode = = MIPS16e_extend_op ) {
pc16 + + ;
__get_user ( mips16inst . full , pc16 ) ;
} else if ( delay_slot ( regs ) ) {
/* skip jump instructions */
/* JAL/JALX are 32 bits but have OPCODE in first short int */
if ( mips16inst . ri . opcode = = MIPS16e_jal_op )
pc16 + + ;
pc16 + + ;
if ( get_user ( mips16inst . full , pc16 ) )
goto sigbus ;
}
switch ( mips16inst . ri . opcode ) {
case MIPS16e_i64_op : /* I64 or RI64 instruction */
switch ( mips16inst . i64 . func ) { /* I64/RI64 func field check */
case MIPS16e_ldpc_func :
case MIPS16e_ldsp_func :
reg = reg16to32 [ mips16inst . ri64 . ry ] ;
goto loadDW ;
case MIPS16e_sdsp_func :
reg = reg16to32 [ mips16inst . ri64 . ry ] ;
goto writeDW ;
case MIPS16e_sdrasp_func :
reg = 29 ; /* GPRSP */
goto writeDW ;
}
goto sigbus ;
case MIPS16e_swsp_op :
case MIPS16e_lwpc_op :
case MIPS16e_lwsp_op :
reg = reg16to32 [ mips16inst . ri . rx ] ;
break ;
case MIPS16e_i8_op :
if ( mips16inst . i8 . func ! = MIPS16e_swrasp_func )
goto sigbus ;
reg = 29 ; /* GPRSP */
break ;
default :
reg = reg16to32 [ mips16inst . rri . ry ] ;
break ;
}
switch ( mips16inst . ri . opcode ) {
case MIPS16e_lb_op :
case MIPS16e_lbu_op :
case MIPS16e_sb_op :
goto sigbus ;
case MIPS16e_lh_op :
if ( ! access_ok ( VERIFY_READ , addr , 2 ) )
goto sigbus ;
LoadHW ( addr , value , res ) ;
if ( res )
goto fault ;
MIPS16e_compute_return_epc ( regs , & oldinst ) ;
regs - > regs [ reg ] = value ;
break ;
case MIPS16e_lhu_op :
if ( ! access_ok ( VERIFY_READ , addr , 2 ) )
goto sigbus ;
LoadHWU ( addr , value , res ) ;
if ( res )
goto fault ;
MIPS16e_compute_return_epc ( regs , & oldinst ) ;
regs - > regs [ reg ] = value ;
break ;
case MIPS16e_lw_op :
case MIPS16e_lwpc_op :
case MIPS16e_lwsp_op :
if ( ! access_ok ( VERIFY_READ , addr , 4 ) )
goto sigbus ;
LoadW ( addr , value , res ) ;
if ( res )
goto fault ;
MIPS16e_compute_return_epc ( regs , & oldinst ) ;
regs - > regs [ reg ] = value ;
break ;
case MIPS16e_lwu_op :
# ifdef CONFIG_64BIT
/*
* A 32 - bit kernel might be running on a 64 - bit processor . But
* if we ' re on a 32 - bit processor and an i - cache incoherency
* or race makes us see a 64 - bit instruction here the sdl / sdr
* would blow up , so for now we don ' t handle unaligned 64 - bit
* instructions on 32 - bit kernels .
*/
if ( ! access_ok ( VERIFY_READ , addr , 4 ) )
goto sigbus ;
LoadWU ( addr , value , res ) ;
if ( res )
goto fault ;
MIPS16e_compute_return_epc ( regs , & oldinst ) ;
regs - > regs [ reg ] = value ;
break ;
# endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill ;
case MIPS16e_ld_op :
loadDW :
# ifdef CONFIG_64BIT
/*
* A 32 - bit kernel might be running on a 64 - bit processor . But
* if we ' re on a 32 - bit processor and an i - cache incoherency
* or race makes us see a 64 - bit instruction here the sdl / sdr
* would blow up , so for now we don ' t handle unaligned 64 - bit
* instructions on 32 - bit kernels .
*/
if ( ! access_ok ( VERIFY_READ , addr , 8 ) )
goto sigbus ;
LoadDW ( addr , value , res ) ;
if ( res )
goto fault ;
MIPS16e_compute_return_epc ( regs , & oldinst ) ;
regs - > regs [ reg ] = value ;
break ;
# endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill ;
case MIPS16e_sh_op :
if ( ! access_ok ( VERIFY_WRITE , addr , 2 ) )
goto sigbus ;
MIPS16e_compute_return_epc ( regs , & oldinst ) ;
value = regs - > regs [ reg ] ;
StoreHW ( addr , value , res ) ;
if ( res )
goto fault ;
break ;
case MIPS16e_sw_op :
case MIPS16e_swsp_op :
case MIPS16e_i8_op : /* actually - MIPS16e_swrasp_func */
if ( ! access_ok ( VERIFY_WRITE , addr , 4 ) )
goto sigbus ;
MIPS16e_compute_return_epc ( regs , & oldinst ) ;
value = regs - > regs [ reg ] ;
StoreW ( addr , value , res ) ;
if ( res )
goto fault ;
break ;
case MIPS16e_sd_op :
writeDW :
# ifdef CONFIG_64BIT
/*
* A 32 - bit kernel might be running on a 64 - bit processor . But
* if we ' re on a 32 - bit processor and an i - cache incoherency
* or race makes us see a 64 - bit instruction here the sdl / sdr
* would blow up , so for now we don ' t handle unaligned 64 - bit
* instructions on 32 - bit kernels .
*/
if ( ! access_ok ( VERIFY_WRITE , addr , 8 ) )
goto sigbus ;
MIPS16e_compute_return_epc ( regs , & oldinst ) ;
value = regs - > regs [ reg ] ;
StoreDW ( addr , value , res ) ;
if ( res )
goto fault ;
break ;
# endif /* CONFIG_64BIT */
/* Cannot handle 64-bit instructions in 32-bit kernel */
goto sigill ;
default :
/*
* Pheeee . . . We encountered an yet unknown instruction or
* cache coherence problem . Die sucker , die . . .
*/
goto sigill ;
}
# ifdef CONFIG_DEBUG_FS
unaligned_instructions + + ;
# endif
return ;
fault :
/* roll back jump/branch */
regs - > cp0_epc = origpc ;
regs - > regs [ 31 ] = orig31 ;
/* Did we have an exception handler installed? */
if ( fixup_exception ( regs ) )
return ;
die_if_kernel ( " Unhandled kernel unaligned access " , regs ) ;
force_sig ( SIGSEGV , current ) ;
return ;
sigbus :
die_if_kernel ( " Unhandled kernel unaligned access " , regs ) ;
force_sig ( SIGBUS , current ) ;
return ;
sigill :
die_if_kernel
( " Unhandled kernel unaligned access or invalid instruction " , regs ) ;
force_sig ( SIGILL , current ) ;
}
2013-06-21 14:10:46 +04:00
2005-04-17 02:20:36 +04:00
asmlinkage void do_ade ( struct pt_regs * regs )
{
2013-05-29 03:07:19 +04:00
enum ctx_state prev_state ;
2005-03-01 22:22:29 +03:00
unsigned int __user * pc ;
2005-04-17 02:20:36 +04:00
mm_segment_t seg ;
2013-05-29 03:07:19 +04:00
prev_state = exception_enter ( ) ;
2010-10-12 15:37:21 +04:00
perf_sw_event ( PERF_COUNT_SW_ALIGNMENT_FAULTS ,
2011-06-27 16:41:57 +04:00
1 , regs , regs - > cp0_badvaddr ) ;
2005-04-17 02:20:36 +04:00
/*
* Did we catch a fault trying to load an instruction ?
*/
2013-03-25 22:18:07 +04:00
if ( regs - > cp0_badvaddr = = regs - > cp0_epc )
2005-04-17 02:20:36 +04:00
goto sigbus ;
2007-07-25 19:19:33 +04:00
if ( user_mode ( regs ) & & ! test_thread_flag ( TIF_FIXADE ) )
2005-04-17 02:20:36 +04:00
goto sigbus ;
2007-06-29 19:55:48 +04:00
if ( unaligned_action = = UNALIGNED_ACTION_SIGNAL )
goto sigbus ;
2005-04-17 02:20:36 +04:00
/*
* Do branch emulation only if we didn ' t forward the exception .
* This is all so but ugly . . .
*/
2013-03-25 22:18:07 +04:00
/*
* Are we running in microMIPS mode ?
*/
if ( get_isa16_mode ( regs - > cp0_epc ) ) {
/*
* Did we catch a fault trying to load an instruction in
* 16 - bit mode ?
*/
if ( regs - > cp0_badvaddr = = msk_isa16_mode ( regs - > cp0_epc ) )
goto sigbus ;
if ( unaligned_action = = UNALIGNED_ACTION_SHOW )
show_registers ( regs ) ;
if ( cpu_has_mmips ) {
seg = get_fs ( ) ;
if ( ! user_mode ( regs ) )
set_fs ( KERNEL_DS ) ;
emulate_load_store_microMIPS ( regs ,
( void __user * ) regs - > cp0_badvaddr ) ;
set_fs ( seg ) ;
return ;
}
2013-03-25 22:46:15 +04:00
if ( cpu_has_mips16 ) {
seg = get_fs ( ) ;
if ( ! user_mode ( regs ) )
set_fs ( KERNEL_DS ) ;
emulate_load_store_MIPS16e ( regs ,
( void __user * ) regs - > cp0_badvaddr ) ;
set_fs ( seg ) ;
return ;
}
2013-03-25 22:18:07 +04:00
goto sigbus ;
}
if ( unaligned_action = = UNALIGNED_ACTION_SHOW )
show_registers ( regs ) ;
pc = ( unsigned int __user * ) exception_epc ( regs ) ;
2005-04-17 02:20:36 +04:00
seg = get_fs ( ) ;
if ( ! user_mode ( regs ) )
set_fs ( KERNEL_DS ) ;
2007-07-29 12:16:19 +04:00
emulate_load_store_insn ( regs , ( void __user * ) regs - > cp0_badvaddr , pc ) ;
2005-04-17 02:20:36 +04:00
set_fs ( seg ) ;
return ;
sigbus :
die_if_kernel ( " Kernel unaligned instruction access " , regs ) ;
force_sig ( SIGBUS , current ) ;
/*
* XXX On return from the signal handler we should advance the epc
*/
2013-05-29 03:07:19 +04:00
exception_exit ( prev_state ) ;
2005-04-17 02:20:36 +04:00
}
2007-06-29 19:55:48 +04:00
# ifdef CONFIG_DEBUG_FS
extern struct dentry * mips_debugfs_dir ;
static int __init debugfs_unaligned ( void )
{
struct dentry * d ;
if ( ! mips_debugfs_dir )
return - ENODEV ;
d = debugfs_create_u32 ( " unaligned_instructions " , S_IRUGO ,
mips_debugfs_dir , & unaligned_instructions ) ;
2008-10-17 15:12:35 +04:00
if ( ! d )
return - ENOMEM ;
2007-06-29 19:55:48 +04:00
d = debugfs_create_u32 ( " unaligned_action " , S_IRUGO | S_IWUSR ,
mips_debugfs_dir , & unaligned_action ) ;
2008-10-17 15:12:35 +04:00
if ( ! d )
return - ENOMEM ;
2007-06-29 19:55:48 +04:00
return 0 ;
}
__initcall ( debugfs_unaligned ) ;
# endif