2008-02-08 15:19:31 +03:00
/* MN10300 Misalignment fixup handler
*
* 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 <linux/module.h>
# include <linux/sched.h>
# include <linux/kernel.h>
# include <linux/string.h>
# include <linux/errno.h>
# include <linux/ptrace.h>
# include <linux/timer.h>
# include <linux/mm.h>
# include <linux/smp.h>
# include <linux/init.h>
# include <linux/delay.h>
# include <linux/spinlock.h>
# include <linux/interrupt.h>
# include <linux/pci.h>
# include <asm/processor.h>
# include <asm/system.h>
# include <asm/uaccess.h>
# include <asm/io.h>
# include <asm/atomic.h>
# include <asm/smp.h>
# include <asm/pgalloc.h>
# include <asm/cpu-regs.h>
# include <asm/busctl-regs.h>
# include <asm/fpu.h>
# include <asm/gdb-stub.h>
# include <asm/asm-offsets.h>
#if 0
2008-11-12 18:34:59 +03:00
# define kdebug(FMT, ...) printk(KERN_DEBUG "MISALIGN: "FMT"\n", ##__VA_ARGS__)
2008-02-08 15:19:31 +03:00
# else
# define kdebug(FMT, ...) do {} while (0)
# endif
2008-11-12 18:35:45 +03:00
static int misalignment_addr ( unsigned long * registers , unsigned long sp ,
unsigned params , unsigned opcode ,
unsigned long disp ,
2008-11-12 18:35:35 +03:00
void * * _address , unsigned long * * _postinc ,
unsigned long * _inc ) ;
2008-02-08 15:19:31 +03:00
static int misalignment_reg ( unsigned long * registers , unsigned params ,
2008-11-12 18:35:14 +03:00
unsigned opcode , unsigned long disp ,
2008-02-08 15:19:31 +03:00
unsigned long * * _register ) ;
2008-11-12 18:35:30 +03:00
static void misalignment_MOV_Lcc ( struct pt_regs * regs , uint32_t opcode ) ;
2008-02-08 15:19:31 +03:00
static const unsigned Dreg_index [ ] = {
REG_D0 > > 2 , REG_D1 > > 2 , REG_D2 > > 2 , REG_D3 > > 2
} ;
static const unsigned Areg_index [ ] = {
REG_A0 > > 2 , REG_A1 > > 2 , REG_A2 > > 2 , REG_A3 > > 2
} ;
static const unsigned Rreg_index [ ] = {
REG_E0 > > 2 , REG_E1 > > 2 , REG_E2 > > 2 , REG_E3 > > 2 ,
REG_E4 > > 2 , REG_E5 > > 2 , REG_E6 > > 2 , REG_E7 > > 2 ,
REG_A0 > > 2 , REG_A1 > > 2 , REG_A2 > > 2 , REG_A3 > > 2 ,
REG_D0 > > 2 , REG_D1 > > 2 , REG_D2 > > 2 , REG_D3 > > 2
} ;
enum format_id {
FMT_S0 ,
FMT_S1 ,
FMT_S2 ,
FMT_S4 ,
FMT_D0 ,
FMT_D1 ,
FMT_D2 ,
FMT_D4 ,
FMT_D6 ,
FMT_D7 ,
FMT_D8 ,
FMT_D9 ,
2008-11-12 18:35:30 +03:00
FMT_D10 ,
2008-02-08 15:19:31 +03:00
} ;
2008-11-12 18:34:59 +03:00
static const struct {
2008-02-08 15:19:31 +03:00
u_int8_t opsz , dispsz ;
} format_tbl [ 16 ] = {
[ FMT_S0 ] = { 8 , 0 } ,
[ FMT_S1 ] = { 8 , 8 } ,
[ FMT_S2 ] = { 8 , 16 } ,
[ FMT_S4 ] = { 8 , 32 } ,
[ FMT_D0 ] = { 16 , 0 } ,
[ FMT_D1 ] = { 16 , 8 } ,
[ FMT_D2 ] = { 16 , 16 } ,
[ FMT_D4 ] = { 16 , 32 } ,
[ FMT_D6 ] = { 24 , 0 } ,
[ FMT_D7 ] = { 24 , 8 } ,
[ FMT_D8 ] = { 24 , 24 } ,
[ FMT_D9 ] = { 24 , 32 } ,
2008-11-12 18:35:30 +03:00
[ FMT_D10 ] = { 32 , 0 } ,
2008-02-08 15:19:31 +03:00
} ;
enum value_id {
DM0 , /* data reg in opcode in bits 0-1 */
DM1 , /* data reg in opcode in bits 2-3 */
DM2 , /* data reg in opcode in bits 4-5 */
AM0 , /* addr reg in opcode in bits 0-1 */
AM1 , /* addr reg in opcode in bits 2-3 */
AM2 , /* addr reg in opcode in bits 4-5 */
RM0 , /* reg in opcode in bits 0-3 */
RM1 , /* reg in opcode in bits 2-5 */
RM2 , /* reg in opcode in bits 4-7 */
RM4 , /* reg in opcode in bits 8-11 */
RM6 , /* reg in opcode in bits 12-15 */
RD0 , /* reg in displacement in bits 0-3 */
RD2 , /* reg in displacement in bits 4-7 */
SP , /* stack pointer */
SD8 , /* 8-bit signed displacement */
SD16 , /* 16-bit signed displacement */
SD24 , /* 24-bit signed displacement */
SIMM4_2 , /* 4-bit signed displacement in opcode bits 4-7 */
SIMM8 , /* 8-bit signed immediate */
2008-11-12 18:35:09 +03:00
IMM8 , /* 8-bit unsigned immediate */
IMM16 , /* 16-bit unsigned immediate */
2008-02-08 15:19:31 +03:00
IMM24 , /* 24-bit unsigned immediate */
IMM32 , /* 32-bit unsigned immediate */
2008-11-12 18:35:09 +03:00
IMM32_HIGH8 , /* 32-bit unsigned immediate, LSB in opcode */
IMM32_MEM , /* 32-bit unsigned displacement */
IMM32_HIGH8_MEM , /* 32-bit unsigned displacement, LSB in opcode */
2008-02-08 15:19:31 +03:00
DN0 = DM0 ,
DN1 = DM1 ,
DN2 = DM2 ,
AN0 = AM0 ,
AN1 = AM1 ,
AN2 = AM2 ,
RN0 = RM0 ,
RN1 = RM1 ,
RN2 = RM2 ,
RN4 = RM4 ,
RN6 = RM6 ,
DI = DM1 ,
RI = RM2 ,
} ;
struct mn10300_opcode {
2008-11-12 18:35:35 +03:00
const char name [ 8 ] ;
2008-02-08 15:19:31 +03:00
u_int32_t opcode ;
u_int32_t opmask ;
unsigned exclusion ;
enum format_id format ;
unsigned cpu_mask ;
# define AM33 330
unsigned params [ 2 ] ;
# define MEM(ADDR) (0x80000000 | (ADDR))
# define MEM2(ADDR1, ADDR2) (0x80000000 | (ADDR1) << 8 | (ADDR2))
# define MEMINC(ADDR) (0x81000000 | (ADDR))
# define MEMINC2(ADDR, INC) (0x81000000 | (ADDR) << 8 | (INC))
} ;
/* LIBOPCODES EXCERPT
Assemble Matsushita MN10300 instructions .
Copyright 1996 , 1997 , 1998 , 1999 , 2000 Free Software Foundation , Inc .
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 .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public Licence for more details .
You should have received a copy of the GNU General Public Licence
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
*/
static const struct mn10300_opcode mn10300_opcodes [ ] = {
2008-11-12 18:35:09 +03:00
{ " mov " , 0x4200 , 0xf300 , 0 , FMT_S1 , 0 , { DM1 , MEM2 ( IMM8 , SP ) } } ,
{ " mov " , 0x4300 , 0xf300 , 0 , FMT_S1 , 0 , { AM1 , MEM2 ( IMM8 , SP ) } } ,
{ " mov " , 0x5800 , 0xfc00 , 0 , FMT_S1 , 0 , { MEM2 ( IMM8 , SP ) , DN0 } } ,
{ " mov " , 0x5c00 , 0xfc00 , 0 , FMT_S1 , 0 , { MEM2 ( IMM8 , SP ) , AN0 } } ,
2008-02-08 15:19:31 +03:00
{ " mov " , 0x60 , 0xf0 , 0 , FMT_S0 , 0 , { DM1 , MEM ( AN0 ) } } ,
{ " mov " , 0x70 , 0xf0 , 0 , FMT_S0 , 0 , { MEM ( AM0 ) , DN1 } } ,
{ " mov " , 0xf000 , 0xfff0 , 0 , FMT_D0 , 0 , { MEM ( AM0 ) , AN1 } } ,
{ " mov " , 0xf010 , 0xfff0 , 0 , FMT_D0 , 0 , { AM1 , MEM ( AN0 ) } } ,
{ " mov " , 0xf300 , 0xffc0 , 0 , FMT_D0 , 0 , { MEM2 ( DI , AM0 ) , DN2 } } ,
{ " mov " , 0xf340 , 0xffc0 , 0 , FMT_D0 , 0 , { DM2 , MEM2 ( DI , AN0 ) } } ,
{ " mov " , 0xf380 , 0xffc0 , 0 , FMT_D0 , 0 , { MEM2 ( DI , AM0 ) , AN2 } } ,
{ " mov " , 0xf3c0 , 0xffc0 , 0 , FMT_D0 , 0 , { AM2 , MEM2 ( DI , AN0 ) } } ,
{ " mov " , 0xf80000 , 0xfff000 , 0 , FMT_D1 , 0 , { MEM2 ( SD8 , AM0 ) , DN1 } } ,
{ " mov " , 0xf81000 , 0xfff000 , 0 , FMT_D1 , 0 , { DM1 , MEM2 ( SD8 , AN0 ) } } ,
{ " mov " , 0xf82000 , 0xfff000 , 0 , FMT_D1 , 0 , { MEM2 ( SD8 , AM0 ) , AN1 } } ,
{ " mov " , 0xf83000 , 0xfff000 , 0 , FMT_D1 , 0 , { AM1 , MEM2 ( SD8 , AN0 ) } } ,
{ " mov " , 0xf90a00 , 0xffff00 , 0 , FMT_D6 , AM33 , { MEM ( RM0 ) , RN2 } } ,
{ " mov " , 0xf91a00 , 0xffff00 , 0 , FMT_D6 , AM33 , { RM2 , MEM ( RN0 ) } } ,
{ " mov " , 0xf96a00 , 0xffff00 , 0x12 , FMT_D6 , AM33 , { MEMINC ( RM0 ) , RN2 } } ,
{ " mov " , 0xf97a00 , 0xffff00 , 0 , FMT_D6 , AM33 , { RM2 , MEMINC ( RN0 ) } } ,
{ " mov " , 0xfa000000 , 0xfff00000 , 0 , FMT_D2 , 0 , { MEM2 ( SD16 , AM0 ) , DN1 } } ,
{ " mov " , 0xfa100000 , 0xfff00000 , 0 , FMT_D2 , 0 , { DM1 , MEM2 ( SD16 , AN0 ) } } ,
{ " mov " , 0xfa200000 , 0xfff00000 , 0 , FMT_D2 , 0 , { MEM2 ( SD16 , AM0 ) , AN1 } } ,
{ " mov " , 0xfa300000 , 0xfff00000 , 0 , FMT_D2 , 0 , { AM1 , MEM2 ( SD16 , AN0 ) } } ,
2008-11-12 18:35:09 +03:00
{ " mov " , 0xfa900000 , 0xfff30000 , 0 , FMT_D2 , 0 , { AM1 , MEM2 ( IMM16 , SP ) } } ,
{ " mov " , 0xfa910000 , 0xfff30000 , 0 , FMT_D2 , 0 , { DM1 , MEM2 ( IMM16 , SP ) } } ,
{ " mov " , 0xfab00000 , 0xfffc0000 , 0 , FMT_D2 , 0 , { MEM2 ( IMM16 , SP ) , AN0 } } ,
{ " mov " , 0xfab40000 , 0xfffc0000 , 0 , FMT_D2 , 0 , { MEM2 ( IMM16 , SP ) , DN0 } } ,
2008-02-08 15:19:31 +03:00
{ " mov " , 0xfb0a0000 , 0xffff0000 , 0 , FMT_D7 , AM33 , { MEM2 ( SD8 , RM0 ) , RN2 } } ,
{ " mov " , 0xfb1a0000 , 0xffff0000 , 0 , FMT_D7 , AM33 , { RM2 , MEM2 ( SD8 , RN0 ) } } ,
{ " mov " , 0xfb6a0000 , 0xffff0000 , 0x22 , FMT_D7 , AM33 , { MEMINC2 ( RM0 , SIMM8 ) , RN2 } } ,
{ " mov " , 0xfb7a0000 , 0xffff0000 , 0 , FMT_D7 , AM33 , { RM2 , MEMINC2 ( RN0 , SIMM8 ) } } ,
2008-11-12 18:35:09 +03:00
{ " mov " , 0xfb8a0000 , 0xffff0f00 , 0 , FMT_D7 , AM33 , { MEM2 ( IMM8 , SP ) , RN2 } } ,
2008-02-08 15:19:31 +03:00
{ " mov " , 0xfb8e0000 , 0xffff000f , 0 , FMT_D7 , AM33 , { MEM2 ( RI , RM0 ) , RD2 } } ,
2008-11-12 18:35:09 +03:00
{ " mov " , 0xfb9a0000 , 0xffff0f00 , 0 , FMT_D7 , AM33 , { RM2 , MEM2 ( IMM8 , SP ) } } ,
2008-02-08 15:19:31 +03:00
{ " mov " , 0xfb9e0000 , 0xffff000f , 0 , FMT_D7 , AM33 , { RD2 , MEM2 ( RI , RN0 ) } } ,
{ " mov " , 0xfc000000 , 0xfff00000 , 0 , FMT_D4 , 0 , { MEM2 ( IMM32 , AM0 ) , DN1 } } ,
{ " mov " , 0xfc100000 , 0xfff00000 , 0 , FMT_D4 , 0 , { DM1 , MEM2 ( IMM32 , AN0 ) } } ,
{ " mov " , 0xfc200000 , 0xfff00000 , 0 , FMT_D4 , 0 , { MEM2 ( IMM32 , AM0 ) , AN1 } } ,
{ " mov " , 0xfc300000 , 0xfff00000 , 0 , FMT_D4 , 0 , { AM1 , MEM2 ( IMM32 , AN0 ) } } ,
2008-11-12 18:35:09 +03:00
{ " mov " , 0xfc800000 , 0xfff30000 , 0 , FMT_D4 , 0 , { AM1 , MEM ( IMM32_MEM ) } } ,
{ " mov " , 0xfc810000 , 0xfff30000 , 0 , FMT_D4 , 0 , { DM1 , MEM ( IMM32_MEM ) } } ,
{ " mov " , 0xfc900000 , 0xfff30000 , 0 , FMT_D4 , 0 , { AM1 , MEM2 ( IMM32 , SP ) } } ,
{ " mov " , 0xfc910000 , 0xfff30000 , 0 , FMT_D4 , 0 , { DM1 , MEM2 ( IMM32 , SP ) } } ,
{ " mov " , 0xfca00000 , 0xfffc0000 , 0 , FMT_D4 , 0 , { MEM ( IMM32_MEM ) , AN0 } } ,
{ " mov " , 0xfca40000 , 0xfffc0000 , 0 , FMT_D4 , 0 , { MEM ( IMM32_MEM ) , DN0 } } ,
{ " mov " , 0xfcb00000 , 0xfffc0000 , 0 , FMT_D4 , 0 , { MEM2 ( IMM32 , SP ) , AN0 } } ,
{ " mov " , 0xfcb40000 , 0xfffc0000 , 0 , FMT_D4 , 0 , { MEM2 ( IMM32 , SP ) , DN0 } } ,
2008-02-08 15:19:31 +03:00
{ " mov " , 0xfd0a0000 , 0xffff0000 , 0 , FMT_D8 , AM33 , { MEM2 ( SD24 , RM0 ) , RN2 } } ,
{ " mov " , 0xfd1a0000 , 0xffff0000 , 0 , FMT_D8 , AM33 , { RM2 , MEM2 ( SD24 , RN0 ) } } ,
{ " mov " , 0xfd6a0000 , 0xffff0000 , 0x22 , FMT_D8 , AM33 , { MEMINC2 ( RM0 , IMM24 ) , RN2 } } ,
{ " mov " , 0xfd7a0000 , 0xffff0000 , 0 , FMT_D8 , AM33 , { RM2 , MEMINC2 ( RN0 , IMM24 ) } } ,
2008-11-12 18:35:09 +03:00
{ " mov " , 0xfd8a0000 , 0xffff0f00 , 0 , FMT_D8 , AM33 , { MEM2 ( IMM24 , SP ) , RN2 } } ,
{ " mov " , 0xfd9a0000 , 0xffff0f00 , 0 , FMT_D8 , AM33 , { RM2 , MEM2 ( IMM24 , SP ) } } ,
{ " mov " , 0xfe0a0000 , 0xffff0000 , 0 , FMT_D9 , AM33 , { MEM2 ( IMM32_HIGH8 , RM0 ) , RN2 } } ,
2008-02-08 15:19:31 +03:00
{ " mov " , 0xfe0a0000 , 0xffff0000 , 0 , FMT_D9 , AM33 , { MEM2 ( IMM32_HIGH8 , RM0 ) , RN2 } } ,
2008-11-12 18:35:09 +03:00
{ " mov " , 0xfe0e0000 , 0xffff0f00 , 0 , FMT_D9 , AM33 , { MEM ( IMM32_HIGH8_MEM ) , RN2 } } ,
2008-02-08 15:19:31 +03:00
{ " mov " , 0xfe1a0000 , 0xffff0000 , 0 , FMT_D9 , AM33 , { RM2 , MEM2 ( IMM32_HIGH8 , RN0 ) } } ,
2008-11-12 18:35:09 +03:00
{ " mov " , 0xfe1a0000 , 0xffff0000 , 0 , FMT_D9 , AM33 , { RM2 , MEM2 ( IMM32_HIGH8 , RN0 ) } } ,
{ " mov " , 0xfe1e0000 , 0xffff0f00 , 0 , FMT_D9 , AM33 , { RM2 , MEM ( IMM32_HIGH8_MEM ) } } ,
2008-02-08 15:19:31 +03:00
{ " mov " , 0xfe6a0000 , 0xffff0000 , 0x22 , FMT_D9 , AM33 , { MEMINC2 ( RM0 , IMM32_HIGH8 ) , RN2 } } ,
{ " mov " , 0xfe7a0000 , 0xffff0000 , 0 , FMT_D9 , AM33 , { RN2 , MEMINC2 ( RM0 , IMM32_HIGH8 ) } } ,
2008-11-12 18:35:09 +03:00
{ " mov " , 0xfe8a0000 , 0xffff0f00 , 0 , FMT_D9 , AM33 , { MEM2 ( IMM32_HIGH8 , SP ) , RN2 } } ,
{ " mov " , 0xfe9a0000 , 0xffff0f00 , 0 , FMT_D9 , AM33 , { RM2 , MEM2 ( IMM32_HIGH8 , SP ) } } ,
2008-02-08 15:19:31 +03:00
{ " movhu " , 0xf060 , 0xfff0 , 0 , FMT_D0 , 0 , { MEM ( AM0 ) , DN1 } } ,
{ " movhu " , 0xf070 , 0xfff0 , 0 , FMT_D0 , 0 , { DM1 , MEM ( AN0 ) } } ,
{ " movhu " , 0xf480 , 0xffc0 , 0 , FMT_D0 , 0 , { MEM2 ( DI , AM0 ) , DN2 } } ,
{ " movhu " , 0xf4c0 , 0xffc0 , 0 , FMT_D0 , 0 , { DM2 , MEM2 ( DI , AN0 ) } } ,
{ " movhu " , 0xf86000 , 0xfff000 , 0 , FMT_D1 , 0 , { MEM2 ( SD8 , AM0 ) , DN1 } } ,
{ " movhu " , 0xf87000 , 0xfff000 , 0 , FMT_D1 , 0 , { DM1 , MEM2 ( SD8 , AN0 ) } } ,
2008-11-12 18:35:09 +03:00
{ " movhu " , 0xf89300 , 0xfff300 , 0 , FMT_D1 , 0 , { DM1 , MEM2 ( IMM8 , SP ) } } ,
{ " movhu " , 0xf8bc00 , 0xfffc00 , 0 , FMT_D1 , 0 , { MEM2 ( IMM8 , SP ) , DN0 } } ,
2008-02-08 15:19:31 +03:00
{ " movhu " , 0xf94a00 , 0xffff00 , 0 , FMT_D6 , AM33 , { MEM ( RM0 ) , RN2 } } ,
{ " movhu " , 0xf95a00 , 0xffff00 , 0 , FMT_D6 , AM33 , { RM2 , MEM ( RN0 ) } } ,
{ " movhu " , 0xf9ea00 , 0xffff00 , 0x12 , FMT_D6 , AM33 , { MEMINC ( RM0 ) , RN2 } } ,
{ " movhu " , 0xf9fa00 , 0xffff00 , 0 , FMT_D6 , AM33 , { RM2 , MEMINC ( RN0 ) } } ,
{ " movhu " , 0xfa600000 , 0xfff00000 , 0 , FMT_D2 , 0 , { MEM2 ( SD16 , AM0 ) , DN1 } } ,
{ " movhu " , 0xfa700000 , 0xfff00000 , 0 , FMT_D2 , 0 , { DM1 , MEM2 ( SD16 , AN0 ) } } ,
2008-11-12 18:35:09 +03:00
{ " movhu " , 0xfa930000 , 0xfff30000 , 0 , FMT_D2 , 0 , { DM1 , MEM2 ( IMM16 , SP ) } } ,
{ " movhu " , 0xfabc0000 , 0xfffc0000 , 0 , FMT_D2 , 0 , { MEM2 ( IMM16 , SP ) , DN0 } } ,
2008-02-08 15:19:31 +03:00
{ " movhu " , 0xfb4a0000 , 0xffff0000 , 0 , FMT_D7 , AM33 , { MEM2 ( SD8 , RM0 ) , RN2 } } ,
{ " movhu " , 0xfb5a0000 , 0xffff0000 , 0 , FMT_D7 , AM33 , { RM2 , MEM2 ( SD8 , RN0 ) } } ,
2008-11-12 18:35:09 +03:00
{ " movhu " , 0xfbca0000 , 0xffff0f00 , 0 , FMT_D7 , AM33 , { MEM2 ( IMM8 , SP ) , RN2 } } ,
2008-02-08 15:19:31 +03:00
{ " movhu " , 0xfbce0000 , 0xffff000f , 0 , FMT_D7 , AM33 , { MEM2 ( RI , RM0 ) , RD2 } } ,
2008-11-12 18:35:09 +03:00
{ " movhu " , 0xfbda0000 , 0xffff0f00 , 0 , FMT_D7 , AM33 , { RM2 , MEM2 ( IMM8 , SP ) } } ,
2008-02-08 15:19:31 +03:00
{ " movhu " , 0xfbde0000 , 0xffff000f , 0 , FMT_D7 , AM33 , { RD2 , MEM2 ( RI , RN0 ) } } ,
{ " movhu " , 0xfbea0000 , 0xffff0000 , 0x22 , FMT_D7 , AM33 , { MEMINC2 ( RM0 , SIMM8 ) , RN2 } } ,
{ " movhu " , 0xfbfa0000 , 0xffff0000 , 0 , FMT_D7 , AM33 , { RM2 , MEMINC2 ( RN0 , SIMM8 ) } } ,
{ " movhu " , 0xfc600000 , 0xfff00000 , 0 , FMT_D4 , 0 , { MEM2 ( IMM32 , AM0 ) , DN1 } } ,
{ " movhu " , 0xfc700000 , 0xfff00000 , 0 , FMT_D4 , 0 , { DM1 , MEM2 ( IMM32 , AN0 ) } } ,
2008-11-12 18:35:09 +03:00
{ " movhu " , 0xfc830000 , 0xfff30000 , 0 , FMT_D4 , 0 , { DM1 , MEM ( IMM32_MEM ) } } ,
{ " movhu " , 0xfc930000 , 0xfff30000 , 0 , FMT_D4 , 0 , { DM1 , MEM2 ( IMM32 , SP ) } } ,
{ " movhu " , 0xfcac0000 , 0xfffc0000 , 0 , FMT_D4 , 0 , { MEM ( IMM32_MEM ) , DN0 } } ,
{ " movhu " , 0xfcbc0000 , 0xfffc0000 , 0 , FMT_D4 , 0 , { MEM2 ( IMM32 , SP ) , DN0 } } ,
2008-02-08 15:19:31 +03:00
{ " movhu " , 0xfd4a0000 , 0xffff0000 , 0 , FMT_D8 , AM33 , { MEM2 ( SD24 , RM0 ) , RN2 } } ,
{ " movhu " , 0xfd5a0000 , 0xffff0000 , 0 , FMT_D8 , AM33 , { RM2 , MEM2 ( SD24 , RN0 ) } } ,
2008-11-12 18:35:09 +03:00
{ " movhu " , 0xfdca0000 , 0xffff0f00 , 0 , FMT_D8 , AM33 , { MEM2 ( IMM24 , SP ) , RN2 } } ,
{ " movhu " , 0xfdda0000 , 0xffff0f00 , 0 , FMT_D8 , AM33 , { RM2 , MEM2 ( IMM24 , SP ) } } ,
2008-02-08 15:19:31 +03:00
{ " movhu " , 0xfdea0000 , 0xffff0000 , 0x22 , FMT_D8 , AM33 , { MEMINC2 ( RM0 , IMM24 ) , RN2 } } ,
{ " movhu " , 0xfdfa0000 , 0xffff0000 , 0 , FMT_D8 , AM33 , { RM2 , MEMINC2 ( RN0 , IMM24 ) } } ,
{ " movhu " , 0xfe4a0000 , 0xffff0000 , 0 , FMT_D9 , AM33 , { MEM2 ( IMM32_HIGH8 , RM0 ) , RN2 } } ,
2008-11-12 18:35:09 +03:00
{ " movhu " , 0xfe4e0000 , 0xffff0f00 , 0 , FMT_D9 , AM33 , { MEM ( IMM32_HIGH8_MEM ) , RN2 } } ,
2008-02-08 15:19:31 +03:00
{ " movhu " , 0xfe5a0000 , 0xffff0000 , 0 , FMT_D9 , AM33 , { RM2 , MEM2 ( IMM32_HIGH8 , RN0 ) } } ,
2008-11-12 18:35:09 +03:00
{ " movhu " , 0xfe5e0000 , 0xffff0f00 , 0 , FMT_D9 , AM33 , { RM2 , MEM ( IMM32_HIGH8_MEM ) } } ,
{ " movhu " , 0xfeca0000 , 0xffff0f00 , 0 , FMT_D9 , AM33 , { MEM2 ( IMM32_HIGH8 , SP ) , RN2 } } ,
{ " movhu " , 0xfeda0000 , 0xffff0f00 , 0 , FMT_D9 , AM33 , { RM2 , MEM2 ( IMM32_HIGH8 , SP ) } } ,
2008-02-08 15:19:31 +03:00
{ " movhu " , 0xfeea0000 , 0xffff0000 , 0x22 , FMT_D9 , AM33 , { MEMINC2 ( RM0 , IMM32_HIGH8 ) , RN2 } } ,
{ " movhu " , 0xfefa0000 , 0xffff0000 , 0 , FMT_D9 , AM33 , { RN2 , MEMINC2 ( RM0 , IMM32_HIGH8 ) } } ,
2008-11-12 18:35:30 +03:00
{ " mov_llt " , 0xf7e00000 , 0xffff000f , 0x22 , FMT_D10 , AM33 , { MEMINC2 ( RN4 , SIMM4_2 ) , RM6 } } ,
{ " mov_lgt " , 0xf7e00001 , 0xffff000f , 0x22 , FMT_D10 , AM33 , { MEMINC2 ( RN4 , SIMM4_2 ) , RM6 } } ,
{ " mov_lge " , 0xf7e00002 , 0xffff000f , 0x22 , FMT_D10 , AM33 , { MEMINC2 ( RN4 , SIMM4_2 ) , RM6 } } ,
{ " mov_lle " , 0xf7e00003 , 0xffff000f , 0x22 , FMT_D10 , AM33 , { MEMINC2 ( RN4 , SIMM4_2 ) , RM6 } } ,
{ " mov_lcs " , 0xf7e00004 , 0xffff000f , 0x22 , FMT_D10 , AM33 , { MEMINC2 ( RN4 , SIMM4_2 ) , RM6 } } ,
{ " mov_lhi " , 0xf7e00005 , 0xffff000f , 0x22 , FMT_D10 , AM33 , { MEMINC2 ( RN4 , SIMM4_2 ) , RM6 } } ,
{ " mov_lcc " , 0xf7e00006 , 0xffff000f , 0x22 , FMT_D10 , AM33 , { MEMINC2 ( RN4 , SIMM4_2 ) , RM6 } } ,
{ " mov_lls " , 0xf7e00007 , 0xffff000f , 0x22 , FMT_D10 , AM33 , { MEMINC2 ( RN4 , SIMM4_2 ) , RM6 } } ,
{ " mov_leq " , 0xf7e00008 , 0xffff000f , 0x22 , FMT_D10 , AM33 , { MEMINC2 ( RN4 , SIMM4_2 ) , RM6 } } ,
{ " mov_lne " , 0xf7e00009 , 0xffff000f , 0x22 , FMT_D10 , AM33 , { MEMINC2 ( RN4 , SIMM4_2 ) , RM6 } } ,
{ " mov_lra " , 0xf7e0000a , 0xffff000f , 0x22 , FMT_D10 , AM33 , { MEMINC2 ( RN4 , SIMM4_2 ) , RM6 } } ,
2008-11-12 18:35:35 +03:00
{ " " , 0 , 0 , 0 , 0 , 0 , { 0 } } ,
2008-02-08 15:19:31 +03:00
} ;
/*
* fix up misalignment problems where possible
*/
asmlinkage void misalignment ( struct pt_regs * regs , enum exception_code code )
{
const struct exception_table_entry * fixup ;
const struct mn10300_opcode * pop ;
unsigned long * registers = ( unsigned long * ) regs ;
2008-11-12 18:35:45 +03:00
unsigned long data , * store , * postinc , disp , inc , sp ;
2008-02-08 15:19:31 +03:00
mm_segment_t seg ;
siginfo_t info ;
2008-11-12 18:35:14 +03:00
uint32_t opcode , noc , xo , xm ;
2008-11-12 18:35:35 +03:00
uint8_t * pc , byte , datasz ;
2008-02-08 15:19:31 +03:00
void * address ;
2008-11-12 18:35:14 +03:00
unsigned tmp , npop , dispsz , loop ;
2008-02-08 15:19:31 +03:00
2008-11-12 18:35:55 +03:00
/* we don't fix up userspace misalignment faults */
2008-11-12 18:35:45 +03:00
if ( user_mode ( regs ) )
2008-11-12 18:35:55 +03:00
goto bus_error ;
sp = ( unsigned long ) regs + sizeof ( * regs ) ;
2008-11-12 18:35:45 +03:00
kdebug ( " ==>misalignment({pc=%lx,sp=%lx}) " , regs - > pc , sp ) ;
2008-02-08 15:19:31 +03:00
if ( regs - > epsw & EPSW_IE )
asm volatile ( " or %0,epsw " : : " i " ( EPSW_IE ) ) ;
seg = get_fs ( ) ;
set_fs ( KERNEL_DS ) ;
fixup = search_exception_tables ( regs - > pc ) ;
/* first thing to do is to match the opcode */
pc = ( u_int8_t * ) regs - > pc ;
if ( __get_user ( byte , pc ) ! = 0 )
goto fetch_error ;
opcode = byte ;
noc = 8 ;
2008-11-12 18:35:35 +03:00
for ( pop = mn10300_opcodes ; pop - > name [ 0 ] ; pop + + ) {
2008-11-12 18:34:59 +03:00
npop = ilog2 ( pop - > opcode | pop - > opmask ) ;
2008-02-08 15:19:31 +03:00
if ( npop < = 0 | | npop > 31 )
continue ;
npop = ( npop + 8 ) & ~ 7 ;
got_more_bits :
if ( npop = = noc ) {
if ( ( opcode & pop - > opmask ) = = pop - > opcode )
goto found_opcode ;
} else if ( npop > noc ) {
xo = pop - > opcode > > ( npop - noc ) ;
xm = pop - > opmask > > ( npop - noc ) ;
if ( ( opcode & xm ) ! = xo )
continue ;
/* we've got a partial match (an exact match on the
* first N bytes ) , so we need to get some more data */
pc + + ;
if ( __get_user ( byte , pc ) ! = 0 )
goto fetch_error ;
opcode = opcode < < 8 | byte ;
noc + = 8 ;
goto got_more_bits ;
} else {
/* there's already been a partial match as long as the
* complete match we ' re now considering , so this one
* should ' t match */
continue ;
}
}
/* didn't manage to find a fixup */
2008-11-12 18:35:55 +03:00
printk ( KERN_CRIT " MISALIGN: %lx: unsupported instruction %x \n " ,
regs - > pc , opcode ) ;
2008-02-08 15:19:31 +03:00
failed :
set_fs ( seg ) ;
if ( die_if_no_fixup ( " misalignment error " , regs , code ) )
return ;
2008-11-12 18:35:55 +03:00
bus_error :
2008-02-08 15:19:31 +03:00
info . si_signo = SIGBUS ;
info . si_errno = 0 ;
info . si_code = BUS_ADRALN ;
info . si_addr = ( void * ) regs - > pc ;
force_sig_info ( SIGBUS , & info , current ) ;
return ;
/* error reading opcodes */
fetch_error :
2008-11-12 18:35:55 +03:00
printk ( KERN_CRIT
" MISALIGN: %p: fault whilst reading instruction data \n " ,
pc ) ;
2008-02-08 15:19:31 +03:00
goto failed ;
bad_addr_mode :
2008-11-12 18:35:55 +03:00
printk ( KERN_CRIT
" MISALIGN: %lx: unsupported addressing mode %x \n " ,
regs - > pc , opcode ) ;
2008-02-08 15:19:31 +03:00
goto failed ;
bad_reg_mode :
2008-11-12 18:35:55 +03:00
printk ( KERN_CRIT
" MISALIGN: %lx: unsupported register mode %x \n " ,
regs - > pc , opcode ) ;
2008-02-08 15:19:31 +03:00
goto failed ;
unsupported_instruction :
2008-11-12 18:35:55 +03:00
printk ( KERN_CRIT
" MISALIGN: %lx: unsupported instruction %x (%s) \n " ,
regs - > pc , opcode , pop - > name ) ;
2008-02-08 15:19:31 +03:00
goto failed ;
transfer_failed :
set_fs ( seg ) ;
if ( fixup ) {
regs - > pc = fixup - > fixup ;
return ;
}
if ( die_if_no_fixup ( " misalignment fixup " , regs , code ) )
return ;
info . si_signo = SIGSEGV ;
info . si_errno = 0 ;
info . si_code = 0 ;
info . si_addr = ( void * ) regs - > pc ;
force_sig_info ( SIGSEGV , & info , current ) ;
return ;
/* we matched the opcode */
found_opcode :
2008-11-12 18:34:59 +03:00
kdebug ( " %lx: %x==%x { %x, %x } " ,
2008-02-08 15:19:31 +03:00
regs - > pc , opcode , pop - > opcode , pop - > params [ 0 ] , pop - > params [ 1 ] ) ;
tmp = format_tbl [ pop - > format ] . opsz ;
if ( tmp > noc )
BUG ( ) ; /* match was less complete than it ought to have been */
if ( tmp < noc ) {
tmp = noc - tmp ;
opcode > > = tmp ;
pc - = tmp > > 3 ;
}
/* grab the extra displacement (note it's LSB first) */
disp = 0 ;
2008-11-12 18:35:14 +03:00
dispsz = format_tbl [ pop - > format ] . dispsz ;
for ( loop = 0 ; loop < dispsz ; loop + = 8 ) {
2008-02-08 15:19:31 +03:00
pc + + ;
if ( __get_user ( byte , pc ) ! = 0 )
goto fetch_error ;
2008-11-12 18:35:14 +03:00
disp | = byte < < loop ;
kdebug ( " {%p} disp[%02x]=%02x " , pc , loop , byte ) ;
2008-02-08 15:19:31 +03:00
}
2008-11-12 18:35:14 +03:00
kdebug ( " disp=%lx " , disp ) ;
2008-02-08 15:19:31 +03:00
set_fs ( KERNEL_XDS ) ;
2008-11-12 18:35:55 +03:00
if ( fixup )
2008-02-08 15:19:31 +03:00
set_fs ( seg ) ;
tmp = ( pop - > params [ 0 ] ^ pop - > params [ 1 ] ) & 0x80000000 ;
if ( ! tmp ) {
2008-11-12 18:35:55 +03:00
printk ( KERN_CRIT
" MISALIGN: %lx: insn not move to/from memory %x \n " ,
regs - > pc , opcode ) ;
2008-02-08 15:19:31 +03:00
goto failed ;
}
2008-11-12 18:35:35 +03:00
/* determine the data transfer size of the move */
if ( pop - > name [ 3 ] = = 0 | | /* "mov" */
pop - > name [ 4 ] = = ' l ' ) /* mov_lcc */
inc = datasz = 4 ;
else if ( pop - > name [ 3 ] = = ' h ' ) /* movhu */
inc = datasz = 2 ;
else
goto unsupported_instruction ;
2008-02-08 15:19:31 +03:00
if ( pop - > params [ 0 ] & 0x80000000 ) {
/* move memory to register */
2008-11-12 18:35:45 +03:00
if ( ! misalignment_addr ( registers , sp ,
pop - > params [ 0 ] , opcode , disp ,
2008-11-12 18:35:35 +03:00
& address , & postinc , & inc ) )
2008-02-08 15:19:31 +03:00
goto bad_addr_mode ;
if ( ! misalignment_reg ( registers , pop - > params [ 1 ] , opcode , disp ,
& store ) )
goto bad_reg_mode ;
2008-11-12 18:35:35 +03:00
kdebug ( " mov%u (%p),DARn " , datasz , address ) ;
if ( copy_from_user ( & data , ( void * ) address , datasz ) ! = 0 )
goto transfer_failed ;
if ( pop - > params [ 0 ] & 0x1000000 ) {
kdebug ( " inc=%lx " , inc ) ;
* postinc + = inc ;
2008-02-08 15:19:31 +03:00
}
* store = data ;
2008-11-12 18:35:30 +03:00
kdebug ( " loaded %lx " , data ) ;
2008-02-08 15:19:31 +03:00
} else {
/* move register to memory */
if ( ! misalignment_reg ( registers , pop - > params [ 0 ] , opcode , disp ,
& store ) )
goto bad_reg_mode ;
2008-11-12 18:35:45 +03:00
if ( ! misalignment_addr ( registers , sp ,
pop - > params [ 1 ] , opcode , disp ,
2008-11-12 18:35:35 +03:00
& address , & postinc , & inc ) )
2008-02-08 15:19:31 +03:00
goto bad_addr_mode ;
data = * store ;
2008-11-12 18:35:35 +03:00
kdebug ( " mov%u %lx,(%p) " , datasz , data , address ) ;
if ( copy_to_user ( ( void * ) address , & data , datasz ) ! = 0 )
goto transfer_failed ;
if ( pop - > params [ 1 ] & 0x1000000 )
* postinc + = inc ;
2008-02-08 15:19:31 +03:00
}
tmp = format_tbl [ pop - > format ] . opsz + format_tbl [ pop - > format ] . dispsz ;
regs - > pc + = tmp > > 3 ;
2008-11-12 18:35:30 +03:00
/* handle MOV_Lcc, which are currently the only FMT_D10 insns that
* access memory */
if ( pop - > format = = FMT_D10 )
misalignment_MOV_Lcc ( regs , opcode ) ;
2008-02-08 15:19:31 +03:00
set_fs ( seg ) ;
}
/*
* determine the address that was being accessed
*/
2008-11-12 18:35:45 +03:00
static int misalignment_addr ( unsigned long * registers , unsigned long sp ,
unsigned params , unsigned opcode ,
unsigned long disp ,
2008-11-12 18:35:35 +03:00
void * * _address , unsigned long * * _postinc ,
unsigned long * _inc )
2008-02-08 15:19:31 +03:00
{
unsigned long * postinc = NULL , address = 0 , tmp ;
2008-11-12 18:35:35 +03:00
if ( ! ( params & 0x1000000 ) ) {
kdebug ( " noinc " ) ;
* _inc = 0 ;
_inc = NULL ;
}
2008-11-12 18:35:20 +03:00
params & = 0x00ffffff ;
2008-02-08 15:19:31 +03:00
do {
switch ( params & 0xff ) {
case DM0 :
postinc = & registers [ Dreg_index [ opcode & 0x03 ] ] ;
address + = * postinc ;
break ;
case DM1 :
2008-11-12 18:35:40 +03:00
postinc = & registers [ Dreg_index [ opcode > > 2 & 0x03 ] ] ;
2008-02-08 15:19:31 +03:00
address + = * postinc ;
break ;
case DM2 :
2008-11-12 18:35:40 +03:00
postinc = & registers [ Dreg_index [ opcode > > 4 & 0x03 ] ] ;
2008-02-08 15:19:31 +03:00
address + = * postinc ;
break ;
case AM0 :
postinc = & registers [ Areg_index [ opcode & 0x03 ] ] ;
address + = * postinc ;
break ;
case AM1 :
2008-11-12 18:35:40 +03:00
postinc = & registers [ Areg_index [ opcode > > 2 & 0x03 ] ] ;
2008-02-08 15:19:31 +03:00
address + = * postinc ;
break ;
case AM2 :
2008-11-12 18:35:40 +03:00
postinc = & registers [ Areg_index [ opcode > > 4 & 0x03 ] ] ;
2008-02-08 15:19:31 +03:00
address + = * postinc ;
break ;
case RM0 :
postinc = & registers [ Rreg_index [ opcode & 0x0f ] ] ;
address + = * postinc ;
break ;
case RM1 :
postinc = & registers [ Rreg_index [ opcode > > 2 & 0x0f ] ] ;
address + = * postinc ;
break ;
case RM2 :
postinc = & registers [ Rreg_index [ opcode > > 4 & 0x0f ] ] ;
address + = * postinc ;
break ;
case RM4 :
postinc = & registers [ Rreg_index [ opcode > > 8 & 0x0f ] ] ;
address + = * postinc ;
break ;
case RM6 :
postinc = & registers [ Rreg_index [ opcode > > 12 & 0x0f ] ] ;
address + = * postinc ;
break ;
case RD0 :
postinc = & registers [ Rreg_index [ disp & 0x0f ] ] ;
address + = * postinc ;
break ;
case RD2 :
postinc = & registers [ Rreg_index [ disp > > 4 & 0x0f ] ] ;
address + = * postinc ;
break ;
2008-11-12 18:35:09 +03:00
case SP :
2008-11-12 18:35:45 +03:00
address + = sp ;
2008-11-12 18:35:09 +03:00
break ;
2008-02-08 15:19:31 +03:00
2008-11-12 18:35:35 +03:00
/* displacements are either to be added to the address
* before use , or , in the case of post - inc addressing ,
* to be added into the base register after use */
2008-02-08 15:19:31 +03:00
case SD8 :
case SIMM8 :
2008-11-12 18:35:35 +03:00
disp = ( long ) ( int8_t ) ( disp & 0xff ) ;
goto displace_or_inc ;
2008-02-08 15:19:31 +03:00
case SD16 :
2008-11-12 18:35:35 +03:00
disp = ( long ) ( int16_t ) ( disp & 0xffff ) ;
goto displace_or_inc ;
2008-02-08 15:19:31 +03:00
case SD24 :
tmp = disp < < 8 ;
asm ( " asr 8,%0 " : " =r " ( tmp ) : " 0 " ( tmp ) ) ;
2008-11-12 18:35:35 +03:00
disp = ( long ) tmp ;
goto displace_or_inc ;
2008-02-08 15:19:31 +03:00
case SIMM4_2 :
tmp = opcode > > 4 & 0x0f ;
tmp < < = 28 ;
asm ( " asr 28,%0 " : " =r " ( tmp ) : " 0 " ( tmp ) ) ;
2008-11-12 18:35:35 +03:00
disp = ( long ) tmp ;
goto displace_or_inc ;
2008-11-12 18:35:45 +03:00
case IMM8 :
disp & = 0x000000ff ;
goto displace_or_inc ;
case IMM16 :
disp & = 0x0000ffff ;
goto displace_or_inc ;
2008-02-08 15:19:31 +03:00
case IMM24 :
2008-11-12 18:35:35 +03:00
disp & = 0x00ffffff ;
goto displace_or_inc ;
2008-02-08 15:19:31 +03:00
case IMM32 :
2008-11-12 18:35:09 +03:00
case IMM32_MEM :
2008-02-08 15:19:31 +03:00
case IMM32_HIGH8 :
2008-11-12 18:35:09 +03:00
case IMM32_HIGH8_MEM :
2008-11-12 18:35:35 +03:00
displace_or_inc :
kdebug ( " %s %lx " , _inc ? " incr " : " disp " , disp ) ;
if ( ! _inc )
address + = disp ;
else
* _inc = disp ;
2008-02-08 15:19:31 +03:00
break ;
default :
2008-11-12 18:35:20 +03:00
BUG ( ) ;
2008-02-08 15:19:31 +03:00
return 0 ;
}
} while ( ( params > > = 8 ) ) ;
* _address = ( void * ) address ;
* _postinc = postinc ;
return 1 ;
}
/*
* determine the register that is acting as source / dest
*/
static int misalignment_reg ( unsigned long * registers , unsigned params ,
2008-11-12 18:35:14 +03:00
unsigned opcode , unsigned long disp ,
2008-02-08 15:19:31 +03:00
unsigned long * * _register )
{
params & = 0x7fffffff ;
if ( params & 0xffffff00 )
return 0 ;
switch ( params & 0xff ) {
case DM0 :
* _register = & registers [ Dreg_index [ opcode & 0x03 ] ] ;
break ;
case DM1 :
* _register = & registers [ Dreg_index [ opcode > > 2 & 0x03 ] ] ;
break ;
case DM2 :
* _register = & registers [ Dreg_index [ opcode > > 4 & 0x03 ] ] ;
break ;
case AM0 :
* _register = & registers [ Areg_index [ opcode & 0x03 ] ] ;
break ;
case AM1 :
* _register = & registers [ Areg_index [ opcode > > 2 & 0x03 ] ] ;
break ;
case AM2 :
* _register = & registers [ Areg_index [ opcode > > 4 & 0x03 ] ] ;
break ;
case RM0 :
* _register = & registers [ Rreg_index [ opcode & 0x0f ] ] ;
break ;
case RM1 :
* _register = & registers [ Rreg_index [ opcode > > 2 & 0x0f ] ] ;
break ;
case RM2 :
* _register = & registers [ Rreg_index [ opcode > > 4 & 0x0f ] ] ;
break ;
case RM4 :
* _register = & registers [ Rreg_index [ opcode > > 8 & 0x0f ] ] ;
break ;
case RM6 :
* _register = & registers [ Rreg_index [ opcode > > 12 & 0x0f ] ] ;
break ;
case RD0 :
* _register = & registers [ Rreg_index [ disp & 0x0f ] ] ;
break ;
case RD2 :
* _register = & registers [ Rreg_index [ disp > > 4 & 0x0f ] ] ;
break ;
case SP :
* _register = & registers [ REG_SP > > 2 ] ;
break ;
default :
2008-11-12 18:35:20 +03:00
BUG ( ) ;
2008-02-08 15:19:31 +03:00
return 0 ;
}
return 1 ;
}
2008-11-12 18:35:04 +03:00
2008-11-12 18:35:30 +03:00
/*
* handle the conditional loop part of the move - and - loop instructions
*/
static void misalignment_MOV_Lcc ( struct pt_regs * regs , uint32_t opcode )
{
unsigned long epsw = regs - > epsw ;
unsigned long NxorV ;
kdebug ( " MOV_Lcc %x [flags=%lx] " , opcode , epsw & 0xf ) ;
/* calculate N^V and shift onto the same bit position as Z */
NxorV = ( ( epsw > > 3 ) ^ epsw > > 1 ) & 1 ;
switch ( opcode & 0xf ) {
case 0x0 : /* MOV_LLT: N^V */
if ( NxorV )
goto take_the_loop ;
return ;
case 0x1 : /* MOV_LGT: ~(Z or (N^V))*/
if ( ! ( ( epsw & EPSW_FLAG_Z ) | NxorV ) )
goto take_the_loop ;
return ;
case 0x2 : /* MOV_LGE: ~(N^V) */
if ( ! NxorV )
goto take_the_loop ;
return ;
case 0x3 : /* MOV_LLE: Z or (N^V) */
if ( ( epsw & EPSW_FLAG_Z ) | NxorV )
goto take_the_loop ;
return ;
case 0x4 : /* MOV_LCS: C */
if ( epsw & EPSW_FLAG_C )
goto take_the_loop ;
return ;
case 0x5 : /* MOV_LHI: ~(C or Z) */
if ( ! ( epsw & ( EPSW_FLAG_C | EPSW_FLAG_Z ) ) )
goto take_the_loop ;
return ;
case 0x6 : /* MOV_LCC: ~C */
if ( ! ( epsw & EPSW_FLAG_C ) )
goto take_the_loop ;
return ;
case 0x7 : /* MOV_LLS: C or Z */
if ( epsw & ( EPSW_FLAG_C | EPSW_FLAG_Z ) )
goto take_the_loop ;
return ;
case 0x8 : /* MOV_LEQ: Z */
if ( epsw & EPSW_FLAG_Z )
goto take_the_loop ;
return ;
case 0x9 : /* MOV_LNE: ~Z */
if ( ! ( epsw & EPSW_FLAG_Z ) )
goto take_the_loop ;
return ;
case 0xa : /* MOV_LRA: always */
goto take_the_loop ;
default :
BUG ( ) ;
}
take_the_loop :
/* wind the PC back to just after the SETLB insn */
kdebug ( " loop LAR=%lx " , regs - > lar ) ;
regs - > pc = regs - > lar - 4 ;
}
2008-11-12 18:35:04 +03:00
/*
* misalignment handler tests
*/
# ifdef CONFIG_TEST_MISALIGNMENT_HANDLER
static u8 __initdata testbuf [ 512 ] __attribute__ ( ( aligned ( 16 ) ) ) = {
[ 257 ] = 0x11 ,
[ 258 ] = 0x22 ,
[ 259 ] = 0x33 ,
[ 260 ] = 0x44 ,
} ;
# define ASSERTCMP(X, OP, Y) \
do { \
if ( unlikely ( ! ( ( X ) OP ( Y ) ) ) ) { \
printk ( KERN_ERR " \n " ) ; \
printk ( KERN_ERR " MISALIGN: Assertion failed at line %u \n " , \
__LINE__ ) ; \
printk ( KERN_ERR " 0x%lx " # OP " 0x%lx is false \n " , \
( unsigned long ) ( X ) , ( unsigned long ) ( Y ) ) ; \
BUG ( ) ; \
} \
} while ( 0 )
static int __init test_misalignment ( void )
{
register void * r asm ( " e0 " ) ;
register u32 y asm ( " e1 " ) ;
void * p = testbuf , * q ;
u32 tmp , tmp2 , x ;
printk ( KERN_NOTICE " ==>test_misalignment() [testbuf=%p] \n " , p ) ;
p + + ;
printk ( KERN_NOTICE " ___ MOV (Am),Dn ___ \n " ) ;
q = p + 256 ;
asm volatile ( " mov (%0) , % 1 " : " + a " (q), " = d " (x)) ;
ASSERTCMP ( q , = = , p + 256 ) ;
ASSERTCMP ( x , = = , 0x44332211 ) ;
printk ( KERN_NOTICE " ___ MOV (256,Am),Dn ___ \n " ) ;
q = p ;
asm volatile ( " mov (256,%0) , % 1 " : " + a " (q), " = d " (x)) ;
ASSERTCMP ( q , = = , p ) ;
ASSERTCMP ( x , = = , 0x44332211 ) ;
printk ( KERN_NOTICE " ___ MOV (Di,Am),Dn ___ \n " ) ;
tmp = 256 ;
q = p ;
asm volatile ( " mov (%2,%0) , % 1 " : " + a " (q), " = d " (x), " + d " (tmp)) ;
ASSERTCMP ( q , = = , p ) ;
ASSERTCMP ( x , = = , 0x44332211 ) ;
ASSERTCMP ( tmp , = = , 256 ) ;
printk ( KERN_NOTICE " ___ MOV (256,Rm),Rn ___ \n " ) ;
r = p ;
asm volatile ( " mov (256,%0) , % 1 " : " + r " (r), " = r " (y)) ;
ASSERTCMP ( r , = = , p ) ;
ASSERTCMP ( y , = = , 0x44332211 ) ;
printk ( KERN_NOTICE " ___ MOV (Rm+),Rn ___ \n " ) ;
r = p + 256 ;
asm volatile ( " mov (%0+) , % 1 " : " + r " (r), " = r " (y)) ;
ASSERTCMP ( r , = = , p + 256 + 4 ) ;
ASSERTCMP ( y , = = , 0x44332211 ) ;
printk ( KERN_NOTICE " ___ MOV (Rm+,8),Rn ___ \n " ) ;
r = p + 256 ;
asm volatile ( " mov (%0+,8) , % 1 " : " + r " (r), " = r " (y)) ;
ASSERTCMP ( r , = = , p + 256 + 8 ) ;
ASSERTCMP ( y , = = , 0x44332211 ) ;
printk ( KERN_NOTICE " ___ MOV (7,SP),Rn ___ \n " ) ;
asm volatile (
" add -16,sp \n "
" mov +0x11,%0 \n "
" movbu %0,(7,sp) \n "
" mov +0x22,%0 \n "
" movbu %0,(8,sp) \n "
" mov +0x33,%0 \n "
" movbu %0,(9,sp) \n "
" mov +0x44,%0 \n "
" movbu %0,(10,sp) \n "
" mov (7,sp),%1 \n "
" add +16,sp \n "
: " +a " ( q ) , " =d " ( x ) ) ;
ASSERTCMP ( x , = = , 0x44332211 ) ;
printk ( KERN_NOTICE " ___ MOV (259,SP),Rn ___ \n " ) ;
asm volatile (
" add -264,sp \n "
" mov +0x11,%0 \n "
" movbu %0,(259,sp) \n "
" mov +0x22,%0 \n "
" movbu %0,(260,sp) \n "
" mov +0x33,%0 \n "
" movbu %0,(261,sp) \n "
" mov +0x55,%0 \n "
" movbu %0,(262,sp) \n "
" mov (259,sp),%1 \n "
" add +264,sp \n "
: " +d " ( tmp ) , " =d " ( x ) ) ;
ASSERTCMP ( x , = = , 0x55332211 ) ;
printk ( KERN_NOTICE " ___ MOV (260,SP),Rn ___ \n " ) ;
asm volatile (
" add -264,sp \n "
" mov +0x11,%0 \n "
" movbu %0,(260,sp) \n "
" mov +0x22,%0 \n "
" movbu %0,(261,sp) \n "
" mov +0x33,%0 \n "
" movbu %0,(262,sp) \n "
" mov +0x55,%0 \n "
" movbu %0,(263,sp) \n "
" mov (260,sp),%1 \n "
" add +264,sp \n "
: " +d " ( tmp ) , " =d " ( x ) ) ;
ASSERTCMP ( x , = = , 0x55332211 ) ;
printk ( KERN_NOTICE " ___ MOV_LNE ___ \n " ) ;
tmp = 1 ;
tmp2 = 2 ;
q = p + 256 ;
asm volatile (
" setlb \n "
" mov %2,%3 \n "
" mov %1,%2 \n "
" cmp +0,%1 \n "
" mov_lne (%0+,4),%1 "
: " +r " ( q ) , " +d " ( tmp ) , " +d " ( tmp2 ) , " =d " ( x )
:
: " cc " ) ;
ASSERTCMP ( q , = = , p + 256 + 12 ) ;
ASSERTCMP ( x , = = , 0x44332211 ) ;
printk ( KERN_NOTICE " ___ MOV in SETLB ___ \n " ) ;
tmp = 1 ;
tmp2 = 2 ;
q = p + 256 ;
asm volatile (
" setlb \n "
" mov %1,%3 \n "
" mov (%0+),%1 \n "
" cmp +0,%1 \n "
" lne "
: " +a " ( q ) , " +d " ( tmp ) , " +d " ( tmp2 ) , " =d " ( x )
:
: " cc " ) ;
ASSERTCMP ( q , = = , p + 256 + 8 ) ;
ASSERTCMP ( x , = = , 0x44332211 ) ;
printk ( KERN_NOTICE " <==test_misalignment() \n " ) ;
return 0 ;
}
arch_initcall ( test_misalignment ) ;
# endif /* CONFIG_TEST_MISALIGNMENT_HANDLER */