2014-06-26 11:41:31 +08: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 .
*
* Copyright ( C ) 2014 Lemote Corporation .
* written by Huacai Chen < chenhc @ lemote . com >
*
* based on arch / mips / cavium - octeon / cpu . c
* Copyright ( C ) 2009 Wind River Systems ,
* written by Ralf Baechle < ralf @ linux - mips . org >
*/
# include <linux/init.h>
# include <linux/sched.h>
# include <linux/notifier.h>
2017-03-08 08:29:31 +01:00
# include <linux/ptrace.h>
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
# include <linux/uaccess.h>
# include <linux/sched/signal.h>
2014-06-26 11:41:31 +08:00
# include <asm/fpu.h>
# include <asm/cop2.h>
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
# include <asm/inst.h>
# include <asm/branch.h>
2014-06-26 11:41:31 +08:00
# include <asm/current.h>
# include <asm/mipsregs.h>
MIPS: Fix build warning about "PTR_STR" redefinition
PTR_STR is redefined when CONFIG_TEST_PRINTF is set. This causes the
following build warning:
CC lib/test_printf.o
lib/test_printf.c:214:0: warning: "PTR_STR" redefined
#define PTR_STR "ffff0123456789ab"
^
In file included from ./arch/mips/include/asm/dsemul.h:11:0,
from ./arch/mips/include/asm/processor.h:22,
from ./arch/mips/include/asm/thread_info.h:16,
from ./include/linux/thread_info.h:38,
from ./include/asm-generic/preempt.h:5,
from ./arch/mips/include/generated/asm/preempt.h:1,
from ./include/linux/preempt.h:78,
from ./include/linux/spinlock.h:51,
from ./include/linux/seqlock.h:36,
from ./include/linux/time.h:6,
from ./include/linux/stat.h:19,
from ./include/linux/module.h:13,
from lib/test_printf.c:10:
./arch/mips/include/asm/inst.h:20:0: note: this is the location of the previous definition
#define PTR_STR ".dword"
^
Instead of renaming PTR_STR we move the unaligned macros to a new file,
which is only included inside MIPS code. This way we can safely include
asm.h and can use STR(PTR) again.
Fixes: e701656ec4db ("MIPS: inst.h: Stop including asm.h to avoid various build failures")
Cc: Maciej W. Rozycki" <macro@linux-mips.org>
Reported-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Co-developed-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-05-30 10:55:25 +02:00
# include <asm/unaligned-emul.h>
2014-06-26 11:41:31 +08:00
static int loongson_cu2_call ( struct notifier_block * nfb , unsigned long action ,
void * data )
{
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
unsigned int res , fpu_owned ;
unsigned long ra , value , value_next ;
union mips_instruction insn ;
2014-06-26 11:41:31 +08:00
int fr = ! test_thread_flag ( TIF_32BIT_FPREGS ) ;
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
struct pt_regs * regs = ( struct pt_regs * ) data ;
void __user * addr = ( void __user * ) regs - > cp0_badvaddr ;
unsigned int __user * pc = ( unsigned int __user * ) exception_epc ( regs ) ;
ra = regs - > regs [ 31 ] ;
__get_user ( insn . word , pc ) ;
2014-06-26 11:41:31 +08:00
switch ( action ) {
case CU2_EXCEPTION :
preempt_disable ( ) ;
2014-08-11 17:10:38 +08:00
fpu_owned = __is_fpu_owner ( ) ;
2014-06-26 11:41:31 +08:00
if ( ! fr )
set_c0_status ( ST0_CU1 | ST0_CU2 ) ;
else
set_c0_status ( ST0_CU1 | ST0_CU2 | ST0_FR ) ;
enable_fpu_hazard ( ) ;
KSTK_STATUS ( current ) | = ( ST0_CU1 | ST0_CU2 ) ;
if ( fr )
KSTK_STATUS ( current ) | = ST0_FR ;
else
KSTK_STATUS ( current ) & = ~ ST0_FR ;
2014-08-11 17:10:38 +08:00
/* If FPU is owned, we needn't init or restore fp */
if ( ! fpu_owned ) {
2014-06-26 11:41:31 +08:00
set_thread_flag ( TIF_USEDFPU ) ;
2018-11-07 23:13:59 +00:00
init_fp_ctx ( current ) ;
_restore_fp ( current ) ;
2014-06-26 11:41:31 +08:00
}
preempt_enable ( ) ;
return NOTIFY_STOP ; /* Don't call default notifier */
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
case CU2_LWC2_OP :
if ( insn . loongson3_lswc2_format . ls = = 0 )
goto sigbus ;
if ( insn . loongson3_lswc2_format . fr = = 0 ) { /* gslq */
if ( ! access_ok ( addr , 16 ) )
goto sigbus ;
LoadDW ( addr , value , res ) ;
if ( res )
goto fault ;
LoadDW ( addr + 8 , value_next , res ) ;
if ( res )
goto fault ;
regs - > regs [ insn . loongson3_lswc2_format . rt ] = value ;
regs - > regs [ insn . loongson3_lswc2_format . rq ] = value_next ;
compute_return_epc ( regs ) ;
} else { /* gslqc1 */
if ( ! access_ok ( addr , 16 ) )
goto sigbus ;
lose_fpu ( 1 ) ;
LoadDW ( addr , value , res ) ;
if ( res )
goto fault ;
LoadDW ( addr + 8 , value_next , res ) ;
if ( res )
goto fault ;
2020-08-24 15:44:03 +08:00
set_fpr64 ( & current - > thread . fpu . fpr [ insn . loongson3_lswc2_format . rt ] , 0 , value ) ;
set_fpr64 ( & current - > thread . fpu . fpr [ insn . loongson3_lswc2_format . rq ] , 0 , value_next ) ;
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
compute_return_epc ( regs ) ;
own_fpu ( 1 ) ;
}
return NOTIFY_STOP ; /* Don't call default notifier */
case CU2_SWC2_OP :
if ( insn . loongson3_lswc2_format . ls = = 0 )
goto sigbus ;
if ( insn . loongson3_lswc2_format . fr = = 0 ) { /* gssq */
if ( ! access_ok ( addr , 16 ) )
goto sigbus ;
/* write upper 8 bytes first */
value_next = regs - > regs [ insn . loongson3_lswc2_format . rq ] ;
StoreDW ( addr + 8 , value_next , res ) ;
if ( res )
goto fault ;
value = regs - > regs [ insn . loongson3_lswc2_format . rt ] ;
StoreDW ( addr , value , res ) ;
if ( res )
goto fault ;
compute_return_epc ( regs ) ;
} else { /* gssqc1 */
if ( ! access_ok ( addr , 16 ) )
goto sigbus ;
lose_fpu ( 1 ) ;
2020-08-24 15:44:03 +08:00
value_next = get_fpr64 ( & current - > thread . fpu . fpr [ insn . loongson3_lswc2_format . rq ] , 0 ) ;
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
StoreDW ( addr + 8 , value_next , res ) ;
if ( res )
goto fault ;
2020-08-24 15:44:03 +08:00
value = get_fpr64 ( & current - > thread . fpu . fpr [ insn . loongson3_lswc2_format . rt ] , 0 ) ;
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
StoreDW ( addr , value , res ) ;
if ( res )
goto fault ;
compute_return_epc ( regs ) ;
own_fpu ( 1 ) ;
}
return NOTIFY_STOP ; /* Don't call default notifier */
case CU2_LDC2_OP :
switch ( insn . loongson3_lsdc2_format . opcode1 ) {
/*
* Loongson - 3 overridden ldc2 instructions .
* opcode1 instruction
* 0x1 gslhx : load 2 bytes to GPR
* 0x2 gslwx : load 4 bytes to GPR
* 0x3 gsldx : load 8 bytes to GPR
* 0x6 gslwxc1 : load 4 bytes to FPR
* 0x7 gsldxc1 : load 8 bytes to FPR
*/
case 0x1 :
if ( ! access_ok ( addr , 2 ) )
goto sigbus ;
LoadHW ( addr , value , res ) ;
if ( res )
goto fault ;
compute_return_epc ( regs ) ;
regs - > regs [ insn . loongson3_lsdc2_format . rt ] = value ;
break ;
case 0x2 :
if ( ! access_ok ( addr , 4 ) )
goto sigbus ;
LoadW ( addr , value , res ) ;
if ( res )
goto fault ;
compute_return_epc ( regs ) ;
regs - > regs [ insn . loongson3_lsdc2_format . rt ] = value ;
break ;
case 0x3 :
if ( ! access_ok ( addr , 8 ) )
goto sigbus ;
LoadDW ( addr , value , res ) ;
if ( res )
goto fault ;
compute_return_epc ( regs ) ;
regs - > regs [ insn . loongson3_lsdc2_format . rt ] = value ;
break ;
case 0x6 :
die_if_kernel ( " Unaligned FP access in kernel code " , regs ) ;
BUG_ON ( ! used_math ( ) ) ;
if ( ! access_ok ( addr , 4 ) )
goto sigbus ;
lose_fpu ( 1 ) ;
LoadW ( addr , value , res ) ;
if ( res )
goto fault ;
2020-08-24 15:44:03 +08:00
set_fpr64 ( & current - > thread . fpu . fpr [ insn . loongson3_lsdc2_format . rt ] , 0 , value ) ;
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
compute_return_epc ( regs ) ;
own_fpu ( 1 ) ;
break ;
case 0x7 :
die_if_kernel ( " Unaligned FP access in kernel code " , regs ) ;
BUG_ON ( ! used_math ( ) ) ;
if ( ! access_ok ( addr , 8 ) )
goto sigbus ;
lose_fpu ( 1 ) ;
LoadDW ( addr , value , res ) ;
if ( res )
goto fault ;
2020-08-24 15:44:03 +08:00
set_fpr64 ( & current - > thread . fpu . fpr [ insn . loongson3_lsdc2_format . rt ] , 0 , value ) ;
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
compute_return_epc ( regs ) ;
own_fpu ( 1 ) ;
break ;
}
return NOTIFY_STOP ; /* Don't call default notifier */
case CU2_SDC2_OP :
switch ( insn . loongson3_lsdc2_format . opcode1 ) {
/*
* Loongson - 3 overridden sdc2 instructions .
* opcode1 instruction
* 0x1 gsshx : store 2 bytes from GPR
* 0x2 gsswx : store 4 bytes from GPR
* 0x3 gssdx : store 8 bytes from GPR
* 0x6 gsswxc1 : store 4 bytes from FPR
* 0x7 gssdxc1 : store 8 bytes from FPR
*/
case 0x1 :
if ( ! access_ok ( addr , 2 ) )
goto sigbus ;
compute_return_epc ( regs ) ;
value = regs - > regs [ insn . loongson3_lsdc2_format . rt ] ;
StoreHW ( addr , value , res ) ;
if ( res )
goto fault ;
break ;
case 0x2 :
if ( ! access_ok ( addr , 4 ) )
goto sigbus ;
compute_return_epc ( regs ) ;
value = regs - > regs [ insn . loongson3_lsdc2_format . rt ] ;
StoreW ( addr , value , res ) ;
if ( res )
goto fault ;
break ;
case 0x3 :
if ( ! access_ok ( addr , 8 ) )
goto sigbus ;
compute_return_epc ( regs ) ;
value = regs - > regs [ insn . loongson3_lsdc2_format . rt ] ;
StoreDW ( addr , value , res ) ;
if ( res )
goto fault ;
break ;
case 0x6 :
die_if_kernel ( " Unaligned FP access in kernel code " , regs ) ;
BUG_ON ( ! used_math ( ) ) ;
if ( ! access_ok ( addr , 4 ) )
goto sigbus ;
lose_fpu ( 1 ) ;
2020-08-24 15:44:03 +08:00
value = get_fpr64 ( & current - > thread . fpu . fpr [ insn . loongson3_lsdc2_format . rt ] , 0 ) ;
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
StoreW ( addr , value , res ) ;
if ( res )
goto fault ;
compute_return_epc ( regs ) ;
own_fpu ( 1 ) ;
break ;
case 0x7 :
die_if_kernel ( " Unaligned FP access in kernel code " , regs ) ;
BUG_ON ( ! used_math ( ) ) ;
if ( ! access_ok ( addr , 8 ) )
goto sigbus ;
lose_fpu ( 1 ) ;
2020-08-24 15:44:03 +08:00
value = get_fpr64 ( & current - > thread . fpu . fpr [ insn . loongson3_lsdc2_format . rt ] , 0 ) ;
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
StoreDW ( addr , value , res ) ;
if ( res )
goto fault ;
compute_return_epc ( regs ) ;
own_fpu ( 1 ) ;
break ;
}
return NOTIFY_STOP ; /* Don't call default notifier */
2014-06-26 11:41:31 +08:00
}
return NOTIFY_OK ; /* Let default notifier send signals */
MIPS: Loongson-3: Add some unaligned instructions emulation
1, Add unaligned gslq, gssq, gslqc1, gssqc1 emulation;
2, Add unaligned gsl{h, w, d}x, gss{h, w, d}x emulation;
3, Add unaligned gslwxc1, gsswxc1, gsldxc1, gssdxc1 emulation.
Signed-off-by: Huacai Chen <chenhc@lemote.com>
Signed-off-by: Pei Huang <huangpei@loongson.cn>
Reviewed-by: Jiaxun Yang <jiaxun.yang@flygoat.com>
Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
2020-04-24 18:56:46 +08:00
fault :
/* roll back jump/branch */
regs - > regs [ 31 ] = ra ;
regs - > cp0_epc = ( unsigned long ) pc ;
/* Did we have an exception handler installed? */
if ( fixup_exception ( regs ) )
return NOTIFY_STOP ; /* Don't call default notifier */
die_if_kernel ( " Unhandled kernel unaligned access " , regs ) ;
force_sig ( SIGSEGV ) ;
return NOTIFY_STOP ; /* Don't call default notifier */
sigbus :
die_if_kernel ( " Unhandled kernel unaligned access " , regs ) ;
force_sig ( SIGBUS ) ;
return NOTIFY_STOP ; /* Don't call default notifier */
2014-06-26 11:41:31 +08:00
}
static int __init loongson_cu2_setup ( void )
{
return cu2_notifier ( loongson_cu2_call , 0 ) ;
}
early_initcall ( loongson_cu2_setup ) ;