misalignment.c revision 292aa141277b142148d15bf28104f8890616e291
1/* MN10300 Misalignment fixup handler 2 * 3 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. 4 * Written by David Howells (dhowells@redhat.com) 5 * 6 * This program is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU General Public Licence 8 * as published by the Free Software Foundation; either version 9 * 2 of the Licence, or (at your option) any later version. 10 */ 11#include <linux/module.h> 12#include <linux/sched.h> 13#include <linux/kernel.h> 14#include <linux/string.h> 15#include <linux/errno.h> 16#include <linux/ptrace.h> 17#include <linux/timer.h> 18#include <linux/mm.h> 19#include <linux/smp.h> 20#include <linux/init.h> 21#include <linux/delay.h> 22#include <linux/spinlock.h> 23#include <linux/interrupt.h> 24#include <linux/pci.h> 25#include <asm/processor.h> 26#include <asm/system.h> 27#include <asm/uaccess.h> 28#include <asm/io.h> 29#include <asm/atomic.h> 30#include <asm/smp.h> 31#include <asm/pgalloc.h> 32#include <asm/cpu-regs.h> 33#include <asm/busctl-regs.h> 34#include <asm/fpu.h> 35#include <asm/gdb-stub.h> 36#include <asm/asm-offsets.h> 37 38#if 0 39#define kdebug(FMT, ...) printk(KERN_DEBUG "MISALIGN: "FMT"\n", ##__VA_ARGS__) 40#else 41#define kdebug(FMT, ...) do {} while (0) 42#endif 43 44static int misalignment_addr(unsigned long *registers, unsigned long sp, 45 unsigned params, unsigned opcode, 46 unsigned long disp, 47 void **_address, unsigned long **_postinc, 48 unsigned long *_inc); 49 50static int misalignment_reg(unsigned long *registers, unsigned params, 51 unsigned opcode, unsigned long disp, 52 unsigned long **_register); 53 54static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode); 55 56static const unsigned Dreg_index[] = { 57 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2 58}; 59 60static const unsigned Areg_index[] = { 61 REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2 62}; 63 64static const unsigned Rreg_index[] = { 65 REG_E0 >> 2, REG_E1 >> 2, REG_E2 >> 2, REG_E3 >> 2, 66 REG_E4 >> 2, REG_E5 >> 2, REG_E6 >> 2, REG_E7 >> 2, 67 REG_A0 >> 2, REG_A1 >> 2, REG_A2 >> 2, REG_A3 >> 2, 68 REG_D0 >> 2, REG_D1 >> 2, REG_D2 >> 2, REG_D3 >> 2 69}; 70 71enum format_id { 72 FMT_S0, 73 FMT_S1, 74 FMT_S2, 75 FMT_S4, 76 FMT_D0, 77 FMT_D1, 78 FMT_D2, 79 FMT_D4, 80 FMT_D6, 81 FMT_D7, 82 FMT_D8, 83 FMT_D9, 84 FMT_D10, 85}; 86 87static const struct { 88 u_int8_t opsz, dispsz; 89} format_tbl[16] = { 90 [FMT_S0] = { 8, 0 }, 91 [FMT_S1] = { 8, 8 }, 92 [FMT_S2] = { 8, 16 }, 93 [FMT_S4] = { 8, 32 }, 94 [FMT_D0] = { 16, 0 }, 95 [FMT_D1] = { 16, 8 }, 96 [FMT_D2] = { 16, 16 }, 97 [FMT_D4] = { 16, 32 }, 98 [FMT_D6] = { 24, 0 }, 99 [FMT_D7] = { 24, 8 }, 100 [FMT_D8] = { 24, 24 }, 101 [FMT_D9] = { 24, 32 }, 102 [FMT_D10] = { 32, 0 }, 103}; 104 105enum value_id { 106 DM0, /* data reg in opcode in bits 0-1 */ 107 DM1, /* data reg in opcode in bits 2-3 */ 108 DM2, /* data reg in opcode in bits 4-5 */ 109 AM0, /* addr reg in opcode in bits 0-1 */ 110 AM1, /* addr reg in opcode in bits 2-3 */ 111 AM2, /* addr reg in opcode in bits 4-5 */ 112 RM0, /* reg in opcode in bits 0-3 */ 113 RM1, /* reg in opcode in bits 2-5 */ 114 RM2, /* reg in opcode in bits 4-7 */ 115 RM4, /* reg in opcode in bits 8-11 */ 116 RM6, /* reg in opcode in bits 12-15 */ 117 118 RD0, /* reg in displacement in bits 0-3 */ 119 RD2, /* reg in displacement in bits 4-7 */ 120 121 SP, /* stack pointer */ 122 123 SD8, /* 8-bit signed displacement */ 124 SD16, /* 16-bit signed displacement */ 125 SD24, /* 24-bit signed displacement */ 126 SIMM4_2, /* 4-bit signed displacement in opcode bits 4-7 */ 127 SIMM8, /* 8-bit signed immediate */ 128 IMM8, /* 8-bit unsigned immediate */ 129 IMM16, /* 16-bit unsigned immediate */ 130 IMM24, /* 24-bit unsigned immediate */ 131 IMM32, /* 32-bit unsigned immediate */ 132 IMM32_HIGH8, /* 32-bit unsigned immediate, LSB in opcode */ 133 134 IMM32_MEM, /* 32-bit unsigned displacement */ 135 IMM32_HIGH8_MEM, /* 32-bit unsigned displacement, LSB in opcode */ 136 137 DN0 = DM0, 138 DN1 = DM1, 139 DN2 = DM2, 140 AN0 = AM0, 141 AN1 = AM1, 142 AN2 = AM2, 143 RN0 = RM0, 144 RN1 = RM1, 145 RN2 = RM2, 146 RN4 = RM4, 147 RN6 = RM6, 148 DI = DM1, 149 RI = RM2, 150 151}; 152 153struct mn10300_opcode { 154 const char name[8]; 155 u_int32_t opcode; 156 u_int32_t opmask; 157 unsigned exclusion; 158 159 enum format_id format; 160 161 unsigned cpu_mask; 162#define AM33 330 163 164 unsigned params[2]; 165#define MEM(ADDR) (0x80000000 | (ADDR)) 166#define MEM2(ADDR1, ADDR2) (0x80000000 | (ADDR1) << 8 | (ADDR2)) 167#define MEMINC(ADDR) (0x81000000 | (ADDR)) 168#define MEMINC2(ADDR, INC) (0x81000000 | (ADDR) << 8 | (INC)) 169}; 170 171/* LIBOPCODES EXCERPT 172 Assemble Matsushita MN10300 instructions. 173 Copyright 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. 174 175 This program is free software; you can redistribute it and/or modify 176 it under the terms of the GNU General Public Licence as published by 177 the Free Software Foundation; either version 2 of the Licence, or 178 (at your option) any later version. 179 180 This program is distributed in the hope that it will be useful, 181 but WITHOUT ANY WARRANTY; without even the implied warranty of 182 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 183 GNU General Public Licence for more details. 184 185 You should have received a copy of the GNU General Public Licence 186 along with this program; if not, write to the Free Software 187 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 188*/ 189static const struct mn10300_opcode mn10300_opcodes[] = { 190{ "mov", 0x4200, 0xf300, 0, FMT_S1, 0, {DM1, MEM2(IMM8, SP)}}, 191{ "mov", 0x4300, 0xf300, 0, FMT_S1, 0, {AM1, MEM2(IMM8, SP)}}, 192{ "mov", 0x5800, 0xfc00, 0, FMT_S1, 0, {MEM2(IMM8, SP), DN0}}, 193{ "mov", 0x5c00, 0xfc00, 0, FMT_S1, 0, {MEM2(IMM8, SP), AN0}}, 194{ "mov", 0x60, 0xf0, 0, FMT_S0, 0, {DM1, MEM(AN0)}}, 195{ "mov", 0x70, 0xf0, 0, FMT_S0, 0, {MEM(AM0), DN1}}, 196{ "mov", 0xf000, 0xfff0, 0, FMT_D0, 0, {MEM(AM0), AN1}}, 197{ "mov", 0xf010, 0xfff0, 0, FMT_D0, 0, {AM1, MEM(AN0)}}, 198{ "mov", 0xf300, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), DN2}}, 199{ "mov", 0xf340, 0xffc0, 0, FMT_D0, 0, {DM2, MEM2(DI, AN0)}}, 200{ "mov", 0xf380, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), AN2}}, 201{ "mov", 0xf3c0, 0xffc0, 0, FMT_D0, 0, {AM2, MEM2(DI, AN0)}}, 202{ "mov", 0xf80000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8, AM0), DN1}}, 203{ "mov", 0xf81000, 0xfff000, 0, FMT_D1, 0, {DM1, MEM2(SD8, AN0)}}, 204{ "mov", 0xf82000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8,AM0), AN1}}, 205{ "mov", 0xf83000, 0xfff000, 0, FMT_D1, 0, {AM1, MEM2(SD8, AN0)}}, 206{ "mov", 0xf90a00, 0xffff00, 0, FMT_D6, AM33, {MEM(RM0), RN2}}, 207{ "mov", 0xf91a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEM(RN0)}}, 208{ "mov", 0xf96a00, 0xffff00, 0x12, FMT_D6, AM33, {MEMINC(RM0), RN2}}, 209{ "mov", 0xf97a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEMINC(RN0)}}, 210{ "mov", 0xfa000000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), DN1}}, 211{ "mov", 0xfa100000, 0xfff00000, 0, FMT_D2, 0, {DM1, MEM2(SD16, AN0)}}, 212{ "mov", 0xfa200000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), AN1}}, 213{ "mov", 0xfa300000, 0xfff00000, 0, FMT_D2, 0, {AM1, MEM2(SD16, AN0)}}, 214{ "mov", 0xfa900000, 0xfff30000, 0, FMT_D2, 0, {AM1, MEM2(IMM16, SP)}}, 215{ "mov", 0xfa910000, 0xfff30000, 0, FMT_D2, 0, {DM1, MEM2(IMM16, SP)}}, 216{ "mov", 0xfab00000, 0xfffc0000, 0, FMT_D2, 0, {MEM2(IMM16, SP), AN0}}, 217{ "mov", 0xfab40000, 0xfffc0000, 0, FMT_D2, 0, {MEM2(IMM16, SP), DN0}}, 218{ "mov", 0xfb0a0000, 0xffff0000, 0, FMT_D7, AM33, {MEM2(SD8, RM0), RN2}}, 219{ "mov", 0xfb1a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEM2(SD8, RN0)}}, 220{ "mov", 0xfb6a0000, 0xffff0000, 0x22, FMT_D7, AM33, {MEMINC2 (RM0, SIMM8), RN2}}, 221{ "mov", 0xfb7a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEMINC2 (RN0, SIMM8)}}, 222{ "mov", 0xfb8a0000, 0xffff0f00, 0, FMT_D7, AM33, {MEM2(IMM8, SP), RN2}}, 223{ "mov", 0xfb8e0000, 0xffff000f, 0, FMT_D7, AM33, {MEM2(RI, RM0), RD2}}, 224{ "mov", 0xfb9a0000, 0xffff0f00, 0, FMT_D7, AM33, {RM2, MEM2(IMM8, SP)}}, 225{ "mov", 0xfb9e0000, 0xffff000f, 0, FMT_D7, AM33, {RD2, MEM2(RI, RN0)}}, 226{ "mov", 0xfc000000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), DN1}}, 227{ "mov", 0xfc100000, 0xfff00000, 0, FMT_D4, 0, {DM1, MEM2(IMM32,AN0)}}, 228{ "mov", 0xfc200000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), AN1}}, 229{ "mov", 0xfc300000, 0xfff00000, 0, FMT_D4, 0, {AM1, MEM2(IMM32,AN0)}}, 230{ "mov", 0xfc800000, 0xfff30000, 0, FMT_D4, 0, {AM1, MEM(IMM32_MEM)}}, 231{ "mov", 0xfc810000, 0xfff30000, 0, FMT_D4, 0, {DM1, MEM(IMM32_MEM)}}, 232{ "mov", 0xfc900000, 0xfff30000, 0, FMT_D4, 0, {AM1, MEM2(IMM32, SP)}}, 233{ "mov", 0xfc910000, 0xfff30000, 0, FMT_D4, 0, {DM1, MEM2(IMM32, SP)}}, 234{ "mov", 0xfca00000, 0xfffc0000, 0, FMT_D4, 0, {MEM(IMM32_MEM), AN0}}, 235{ "mov", 0xfca40000, 0xfffc0000, 0, FMT_D4, 0, {MEM(IMM32_MEM), DN0}}, 236{ "mov", 0xfcb00000, 0xfffc0000, 0, FMT_D4, 0, {MEM2(IMM32, SP), AN0}}, 237{ "mov", 0xfcb40000, 0xfffc0000, 0, FMT_D4, 0, {MEM2(IMM32, SP), DN0}}, 238{ "mov", 0xfd0a0000, 0xffff0000, 0, FMT_D8, AM33, {MEM2(SD24, RM0), RN2}}, 239{ "mov", 0xfd1a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEM2(SD24, RN0)}}, 240{ "mov", 0xfd6a0000, 0xffff0000, 0x22, FMT_D8, AM33, {MEMINC2 (RM0, IMM24), RN2}}, 241{ "mov", 0xfd7a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEMINC2 (RN0, IMM24)}}, 242{ "mov", 0xfd8a0000, 0xffff0f00, 0, FMT_D8, AM33, {MEM2(IMM24, SP), RN2}}, 243{ "mov", 0xfd9a0000, 0xffff0f00, 0, FMT_D8, AM33, {RM2, MEM2(IMM24, SP)}}, 244{ "mov", 0xfe0a0000, 0xffff0000, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8,RM0), RN2}}, 245{ "mov", 0xfe0a0000, 0xffff0000, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8,RM0), RN2}}, 246{ "mov", 0xfe0e0000, 0xffff0f00, 0, FMT_D9, AM33, {MEM(IMM32_HIGH8_MEM), RN2}}, 247{ "mov", 0xfe1a0000, 0xffff0000, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, RN0)}}, 248{ "mov", 0xfe1a0000, 0xffff0000, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, RN0)}}, 249{ "mov", 0xfe1e0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM(IMM32_HIGH8_MEM)}}, 250{ "mov", 0xfe6a0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}}, 251{ "mov", 0xfe7a0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}}, 252{ "mov", 0xfe8a0000, 0xffff0f00, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8, SP), RN2}}, 253{ "mov", 0xfe9a0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, SP)}}, 254 255{ "movhu", 0xf060, 0xfff0, 0, FMT_D0, 0, {MEM(AM0), DN1}}, 256{ "movhu", 0xf070, 0xfff0, 0, FMT_D0, 0, {DM1, MEM(AN0)}}, 257{ "movhu", 0xf480, 0xffc0, 0, FMT_D0, 0, {MEM2(DI, AM0), DN2}}, 258{ "movhu", 0xf4c0, 0xffc0, 0, FMT_D0, 0, {DM2, MEM2(DI, AN0)}}, 259{ "movhu", 0xf86000, 0xfff000, 0, FMT_D1, 0, {MEM2(SD8, AM0), DN1}}, 260{ "movhu", 0xf87000, 0xfff000, 0, FMT_D1, 0, {DM1, MEM2(SD8, AN0)}}, 261{ "movhu", 0xf89300, 0xfff300, 0, FMT_D1, 0, {DM1, MEM2(IMM8, SP)}}, 262{ "movhu", 0xf8bc00, 0xfffc00, 0, FMT_D1, 0, {MEM2(IMM8, SP), DN0}}, 263{ "movhu", 0xf94a00, 0xffff00, 0, FMT_D6, AM33, {MEM(RM0), RN2}}, 264{ "movhu", 0xf95a00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEM(RN0)}}, 265{ "movhu", 0xf9ea00, 0xffff00, 0x12, FMT_D6, AM33, {MEMINC(RM0), RN2}}, 266{ "movhu", 0xf9fa00, 0xffff00, 0, FMT_D6, AM33, {RM2, MEMINC(RN0)}}, 267{ "movhu", 0xfa600000, 0xfff00000, 0, FMT_D2, 0, {MEM2(SD16, AM0), DN1}}, 268{ "movhu", 0xfa700000, 0xfff00000, 0, FMT_D2, 0, {DM1, MEM2(SD16, AN0)}}, 269{ "movhu", 0xfa930000, 0xfff30000, 0, FMT_D2, 0, {DM1, MEM2(IMM16, SP)}}, 270{ "movhu", 0xfabc0000, 0xfffc0000, 0, FMT_D2, 0, {MEM2(IMM16, SP), DN0}}, 271{ "movhu", 0xfb4a0000, 0xffff0000, 0, FMT_D7, AM33, {MEM2(SD8, RM0), RN2}}, 272{ "movhu", 0xfb5a0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEM2(SD8, RN0)}}, 273{ "movhu", 0xfbca0000, 0xffff0f00, 0, FMT_D7, AM33, {MEM2(IMM8, SP), RN2}}, 274{ "movhu", 0xfbce0000, 0xffff000f, 0, FMT_D7, AM33, {MEM2(RI, RM0), RD2}}, 275{ "movhu", 0xfbda0000, 0xffff0f00, 0, FMT_D7, AM33, {RM2, MEM2(IMM8, SP)}}, 276{ "movhu", 0xfbde0000, 0xffff000f, 0, FMT_D7, AM33, {RD2, MEM2(RI, RN0)}}, 277{ "movhu", 0xfbea0000, 0xffff0000, 0x22, FMT_D7, AM33, {MEMINC2 (RM0, SIMM8), RN2}}, 278{ "movhu", 0xfbfa0000, 0xffff0000, 0, FMT_D7, AM33, {RM2, MEMINC2 (RN0, SIMM8)}}, 279{ "movhu", 0xfc600000, 0xfff00000, 0, FMT_D4, 0, {MEM2(IMM32,AM0), DN1}}, 280{ "movhu", 0xfc700000, 0xfff00000, 0, FMT_D4, 0, {DM1, MEM2(IMM32,AN0)}}, 281{ "movhu", 0xfc830000, 0xfff30000, 0, FMT_D4, 0, {DM1, MEM(IMM32_MEM)}}, 282{ "movhu", 0xfc930000, 0xfff30000, 0, FMT_D4, 0, {DM1, MEM2(IMM32, SP)}}, 283{ "movhu", 0xfcac0000, 0xfffc0000, 0, FMT_D4, 0, {MEM(IMM32_MEM), DN0}}, 284{ "movhu", 0xfcbc0000, 0xfffc0000, 0, FMT_D4, 0, {MEM2(IMM32, SP), DN0}}, 285{ "movhu", 0xfd4a0000, 0xffff0000, 0, FMT_D8, AM33, {MEM2(SD24, RM0), RN2}}, 286{ "movhu", 0xfd5a0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEM2(SD24, RN0)}}, 287{ "movhu", 0xfdca0000, 0xffff0f00, 0, FMT_D8, AM33, {MEM2(IMM24, SP), RN2}}, 288{ "movhu", 0xfdda0000, 0xffff0f00, 0, FMT_D8, AM33, {RM2, MEM2(IMM24, SP)}}, 289{ "movhu", 0xfdea0000, 0xffff0000, 0x22, FMT_D8, AM33, {MEMINC2 (RM0, IMM24), RN2}}, 290{ "movhu", 0xfdfa0000, 0xffff0000, 0, FMT_D8, AM33, {RM2, MEMINC2 (RN0, IMM24)}}, 291{ "movhu", 0xfe4a0000, 0xffff0000, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8,RM0), RN2}}, 292{ "movhu", 0xfe4e0000, 0xffff0f00, 0, FMT_D9, AM33, {MEM(IMM32_HIGH8_MEM), RN2}}, 293{ "movhu", 0xfe5a0000, 0xffff0000, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, RN0)}}, 294{ "movhu", 0xfe5e0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM(IMM32_HIGH8_MEM)}}, 295{ "movhu", 0xfeca0000, 0xffff0f00, 0, FMT_D9, AM33, {MEM2(IMM32_HIGH8, SP), RN2}}, 296{ "movhu", 0xfeda0000, 0xffff0f00, 0, FMT_D9, AM33, {RM2, MEM2(IMM32_HIGH8, SP)}}, 297{ "movhu", 0xfeea0000, 0xffff0000, 0x22, FMT_D9, AM33, {MEMINC2 (RM0, IMM32_HIGH8), RN2}}, 298{ "movhu", 0xfefa0000, 0xffff0000, 0, FMT_D9, AM33, {RN2, MEMINC2 (RM0, IMM32_HIGH8)}}, 299 300{ "mov_llt", 0xf7e00000, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 301{ "mov_lgt", 0xf7e00001, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 302{ "mov_lge", 0xf7e00002, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 303{ "mov_lle", 0xf7e00003, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 304{ "mov_lcs", 0xf7e00004, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 305{ "mov_lhi", 0xf7e00005, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 306{ "mov_lcc", 0xf7e00006, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 307{ "mov_lls", 0xf7e00007, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 308{ "mov_leq", 0xf7e00008, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 309{ "mov_lne", 0xf7e00009, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 310{ "mov_lra", 0xf7e0000a, 0xffff000f, 0x22, FMT_D10, AM33, {MEMINC2 (RN4,SIMM4_2), RM6}}, 311 312{ "", 0, 0, 0, 0, 0, {0}}, 313}; 314 315/* 316 * fix up misalignment problems where possible 317 */ 318asmlinkage void misalignment(struct pt_regs *regs, enum exception_code code) 319{ 320 const struct exception_table_entry *fixup; 321 const struct mn10300_opcode *pop; 322 unsigned long *registers = (unsigned long *) regs; 323 unsigned long data, *store, *postinc, disp, inc, sp; 324 mm_segment_t seg; 325 siginfo_t info; 326 uint32_t opcode, noc, xo, xm; 327 uint8_t *pc, byte, datasz; 328 void *address; 329 unsigned tmp, npop, dispsz, loop; 330 331 /* we don't fix up userspace misalignment faults */ 332 if (user_mode(regs)) 333 goto bus_error; 334 335 sp = (unsigned long) regs + sizeof(*regs); 336 337 kdebug("==>misalignment({pc=%lx,sp=%lx})", regs->pc, sp); 338 339 if (regs->epsw & EPSW_IE) 340 asm volatile("or %0,epsw" : : "i"(EPSW_IE)); 341 342 seg = get_fs(); 343 set_fs(KERNEL_DS); 344 345 fixup = search_exception_tables(regs->pc); 346 347 /* first thing to do is to match the opcode */ 348 pc = (u_int8_t *) regs->pc; 349 350 if (__get_user(byte, pc) != 0) 351 goto fetch_error; 352 opcode = byte; 353 noc = 8; 354 355 for (pop = mn10300_opcodes; pop->name[0]; pop++) { 356 npop = ilog2(pop->opcode | pop->opmask); 357 if (npop <= 0 || npop > 31) 358 continue; 359 npop = (npop + 8) & ~7; 360 361 got_more_bits: 362 if (npop == noc) { 363 if ((opcode & pop->opmask) == pop->opcode) 364 goto found_opcode; 365 } else if (npop > noc) { 366 xo = pop->opcode >> (npop - noc); 367 xm = pop->opmask >> (npop - noc); 368 369 if ((opcode & xm) != xo) 370 continue; 371 372 /* we've got a partial match (an exact match on the 373 * first N bytes), so we need to get some more data */ 374 pc++; 375 if (__get_user(byte, pc) != 0) 376 goto fetch_error; 377 opcode = opcode << 8 | byte; 378 noc += 8; 379 goto got_more_bits; 380 } else { 381 /* there's already been a partial match as long as the 382 * complete match we're now considering, so this one 383 * should't match */ 384 continue; 385 } 386 } 387 388 /* didn't manage to find a fixup */ 389 printk(KERN_CRIT "MISALIGN: %lx: unsupported instruction %x\n", 390 regs->pc, opcode); 391 392failed: 393 set_fs(seg); 394 if (die_if_no_fixup("misalignment error", regs, code)) 395 return; 396 397bus_error: 398 info.si_signo = SIGBUS; 399 info.si_errno = 0; 400 info.si_code = BUS_ADRALN; 401 info.si_addr = (void *) regs->pc; 402 force_sig_info(SIGBUS, &info, current); 403 return; 404 405 /* error reading opcodes */ 406fetch_error: 407 printk(KERN_CRIT 408 "MISALIGN: %p: fault whilst reading instruction data\n", 409 pc); 410 goto failed; 411 412bad_addr_mode: 413 printk(KERN_CRIT 414 "MISALIGN: %lx: unsupported addressing mode %x\n", 415 regs->pc, opcode); 416 goto failed; 417 418bad_reg_mode: 419 printk(KERN_CRIT 420 "MISALIGN: %lx: unsupported register mode %x\n", 421 regs->pc, opcode); 422 goto failed; 423 424unsupported_instruction: 425 printk(KERN_CRIT 426 "MISALIGN: %lx: unsupported instruction %x (%s)\n", 427 regs->pc, opcode, pop->name); 428 goto failed; 429 430transfer_failed: 431 set_fs(seg); 432 if (fixup) { 433 regs->pc = fixup->fixup; 434 return; 435 } 436 if (die_if_no_fixup("misalignment fixup", regs, code)) 437 return; 438 439 info.si_signo = SIGSEGV; 440 info.si_errno = 0; 441 info.si_code = 0; 442 info.si_addr = (void *) regs->pc; 443 force_sig_info(SIGSEGV, &info, current); 444 return; 445 446 /* we matched the opcode */ 447found_opcode: 448 kdebug("%lx: %x==%x { %x, %x }", 449 regs->pc, opcode, pop->opcode, pop->params[0], pop->params[1]); 450 451 tmp = format_tbl[pop->format].opsz; 452 BUG_ON(tmp > noc); /* match was less complete than it ought to have been */ 453 454 if (tmp < noc) { 455 tmp = noc - tmp; 456 opcode >>= tmp; 457 pc -= tmp >> 3; 458 } 459 460 /* grab the extra displacement (note it's LSB first) */ 461 disp = 0; 462 dispsz = format_tbl[pop->format].dispsz; 463 for (loop = 0; loop < dispsz; loop += 8) { 464 pc++; 465 if (__get_user(byte, pc) != 0) 466 goto fetch_error; 467 disp |= byte << loop; 468 kdebug("{%p} disp[%02x]=%02x", pc, loop, byte); 469 } 470 471 kdebug("disp=%lx", disp); 472 473 set_fs(KERNEL_XDS); 474 if (fixup) 475 set_fs(seg); 476 477 tmp = (pop->params[0] ^ pop->params[1]) & 0x80000000; 478 if (!tmp) { 479 printk(KERN_CRIT 480 "MISALIGN: %lx: insn not move to/from memory %x\n", 481 regs->pc, opcode); 482 goto failed; 483 } 484 485 /* determine the data transfer size of the move */ 486 if (pop->name[3] == 0 || /* "mov" */ 487 pop->name[4] == 'l') /* mov_lcc */ 488 inc = datasz = 4; 489 else if (pop->name[3] == 'h') /* movhu */ 490 inc = datasz = 2; 491 else 492 goto unsupported_instruction; 493 494 if (pop->params[0] & 0x80000000) { 495 /* move memory to register */ 496 if (!misalignment_addr(registers, sp, 497 pop->params[0], opcode, disp, 498 &address, &postinc, &inc)) 499 goto bad_addr_mode; 500 501 if (!misalignment_reg(registers, pop->params[1], opcode, disp, 502 &store)) 503 goto bad_reg_mode; 504 505 kdebug("mov%u (%p),DARn", datasz, address); 506 if (copy_from_user(&data, (void *) address, datasz) != 0) 507 goto transfer_failed; 508 if (pop->params[0] & 0x1000000) { 509 kdebug("inc=%lx", inc); 510 *postinc += inc; 511 } 512 513 *store = data; 514 kdebug("loaded %lx", data); 515 } else { 516 /* move register to memory */ 517 if (!misalignment_reg(registers, pop->params[0], opcode, disp, 518 &store)) 519 goto bad_reg_mode; 520 521 if (!misalignment_addr(registers, sp, 522 pop->params[1], opcode, disp, 523 &address, &postinc, &inc)) 524 goto bad_addr_mode; 525 526 data = *store; 527 528 kdebug("mov%u %lx,(%p)", datasz, data, address); 529 if (copy_to_user((void *) address, &data, datasz) != 0) 530 goto transfer_failed; 531 if (pop->params[1] & 0x1000000) 532 *postinc += inc; 533 } 534 535 tmp = format_tbl[pop->format].opsz + format_tbl[pop->format].dispsz; 536 regs->pc += tmp >> 3; 537 538 /* handle MOV_Lcc, which are currently the only FMT_D10 insns that 539 * access memory */ 540 if (pop->format == FMT_D10) 541 misalignment_MOV_Lcc(regs, opcode); 542 543 set_fs(seg); 544} 545 546/* 547 * determine the address that was being accessed 548 */ 549static int misalignment_addr(unsigned long *registers, unsigned long sp, 550 unsigned params, unsigned opcode, 551 unsigned long disp, 552 void **_address, unsigned long **_postinc, 553 unsigned long *_inc) 554{ 555 unsigned long *postinc = NULL, address = 0, tmp; 556 557 if (!(params & 0x1000000)) { 558 kdebug("noinc"); 559 *_inc = 0; 560 _inc = NULL; 561 } 562 563 params &= 0x00ffffff; 564 565 do { 566 switch (params & 0xff) { 567 case DM0: 568 postinc = ®isters[Dreg_index[opcode & 0x03]]; 569 address += *postinc; 570 break; 571 case DM1: 572 postinc = ®isters[Dreg_index[opcode >> 2 & 0x03]]; 573 address += *postinc; 574 break; 575 case DM2: 576 postinc = ®isters[Dreg_index[opcode >> 4 & 0x03]]; 577 address += *postinc; 578 break; 579 case AM0: 580 postinc = ®isters[Areg_index[opcode & 0x03]]; 581 address += *postinc; 582 break; 583 case AM1: 584 postinc = ®isters[Areg_index[opcode >> 2 & 0x03]]; 585 address += *postinc; 586 break; 587 case AM2: 588 postinc = ®isters[Areg_index[opcode >> 4 & 0x03]]; 589 address += *postinc; 590 break; 591 case RM0: 592 postinc = ®isters[Rreg_index[opcode & 0x0f]]; 593 address += *postinc; 594 break; 595 case RM1: 596 postinc = ®isters[Rreg_index[opcode >> 2 & 0x0f]]; 597 address += *postinc; 598 break; 599 case RM2: 600 postinc = ®isters[Rreg_index[opcode >> 4 & 0x0f]]; 601 address += *postinc; 602 break; 603 case RM4: 604 postinc = ®isters[Rreg_index[opcode >> 8 & 0x0f]]; 605 address += *postinc; 606 break; 607 case RM6: 608 postinc = ®isters[Rreg_index[opcode >> 12 & 0x0f]]; 609 address += *postinc; 610 break; 611 case RD0: 612 postinc = ®isters[Rreg_index[disp & 0x0f]]; 613 address += *postinc; 614 break; 615 case RD2: 616 postinc = ®isters[Rreg_index[disp >> 4 & 0x0f]]; 617 address += *postinc; 618 break; 619 case SP: 620 address += sp; 621 break; 622 623 /* displacements are either to be added to the address 624 * before use, or, in the case of post-inc addressing, 625 * to be added into the base register after use */ 626 case SD8: 627 case SIMM8: 628 disp = (long) (int8_t) (disp & 0xff); 629 goto displace_or_inc; 630 case SD16: 631 disp = (long) (int16_t) (disp & 0xffff); 632 goto displace_or_inc; 633 case SD24: 634 tmp = disp << 8; 635 asm("asr 8,%0" : "=r"(tmp) : "0"(tmp) : "cc"); 636 disp = (long) tmp; 637 goto displace_or_inc; 638 case SIMM4_2: 639 tmp = opcode >> 4 & 0x0f; 640 tmp <<= 28; 641 asm("asr 28,%0" : "=r"(tmp) : "0"(tmp) : "cc"); 642 disp = (long) tmp; 643 goto displace_or_inc; 644 case IMM8: 645 disp &= 0x000000ff; 646 goto displace_or_inc; 647 case IMM16: 648 disp &= 0x0000ffff; 649 goto displace_or_inc; 650 case IMM24: 651 disp &= 0x00ffffff; 652 goto displace_or_inc; 653 case IMM32: 654 case IMM32_MEM: 655 case IMM32_HIGH8: 656 case IMM32_HIGH8_MEM: 657 displace_or_inc: 658 kdebug("%s %lx", _inc ? "incr" : "disp", disp); 659 if (!_inc) 660 address += disp; 661 else 662 *_inc = disp; 663 break; 664 default: 665 BUG(); 666 return 0; 667 } 668 } while ((params >>= 8)); 669 670 *_address = (void *) address; 671 *_postinc = postinc; 672 return 1; 673} 674 675/* 676 * determine the register that is acting as source/dest 677 */ 678static int misalignment_reg(unsigned long *registers, unsigned params, 679 unsigned opcode, unsigned long disp, 680 unsigned long **_register) 681{ 682 params &= 0x7fffffff; 683 684 if (params & 0xffffff00) 685 return 0; 686 687 switch (params & 0xff) { 688 case DM0: 689 *_register = ®isters[Dreg_index[opcode & 0x03]]; 690 break; 691 case DM1: 692 *_register = ®isters[Dreg_index[opcode >> 2 & 0x03]]; 693 break; 694 case DM2: 695 *_register = ®isters[Dreg_index[opcode >> 4 & 0x03]]; 696 break; 697 case AM0: 698 *_register = ®isters[Areg_index[opcode & 0x03]]; 699 break; 700 case AM1: 701 *_register = ®isters[Areg_index[opcode >> 2 & 0x03]]; 702 break; 703 case AM2: 704 *_register = ®isters[Areg_index[opcode >> 4 & 0x03]]; 705 break; 706 case RM0: 707 *_register = ®isters[Rreg_index[opcode & 0x0f]]; 708 break; 709 case RM1: 710 *_register = ®isters[Rreg_index[opcode >> 2 & 0x0f]]; 711 break; 712 case RM2: 713 *_register = ®isters[Rreg_index[opcode >> 4 & 0x0f]]; 714 break; 715 case RM4: 716 *_register = ®isters[Rreg_index[opcode >> 8 & 0x0f]]; 717 break; 718 case RM6: 719 *_register = ®isters[Rreg_index[opcode >> 12 & 0x0f]]; 720 break; 721 case RD0: 722 *_register = ®isters[Rreg_index[disp & 0x0f]]; 723 break; 724 case RD2: 725 *_register = ®isters[Rreg_index[disp >> 4 & 0x0f]]; 726 break; 727 case SP: 728 *_register = ®isters[REG_SP >> 2]; 729 break; 730 731 default: 732 BUG(); 733 return 0; 734 } 735 736 return 1; 737} 738 739/* 740 * handle the conditional loop part of the move-and-loop instructions 741 */ 742static void misalignment_MOV_Lcc(struct pt_regs *regs, uint32_t opcode) 743{ 744 unsigned long epsw = regs->epsw; 745 unsigned long NxorV; 746 747 kdebug("MOV_Lcc %x [flags=%lx]", opcode, epsw & 0xf); 748 749 /* calculate N^V and shift onto the same bit position as Z */ 750 NxorV = ((epsw >> 3) ^ epsw >> 1) & 1; 751 752 switch (opcode & 0xf) { 753 case 0x0: /* MOV_LLT: N^V */ 754 if (NxorV) 755 goto take_the_loop; 756 return; 757 case 0x1: /* MOV_LGT: ~(Z or (N^V))*/ 758 if (!((epsw & EPSW_FLAG_Z) | NxorV)) 759 goto take_the_loop; 760 return; 761 case 0x2: /* MOV_LGE: ~(N^V) */ 762 if (!NxorV) 763 goto take_the_loop; 764 return; 765 case 0x3: /* MOV_LLE: Z or (N^V) */ 766 if ((epsw & EPSW_FLAG_Z) | NxorV) 767 goto take_the_loop; 768 return; 769 770 case 0x4: /* MOV_LCS: C */ 771 if (epsw & EPSW_FLAG_C) 772 goto take_the_loop; 773 return; 774 case 0x5: /* MOV_LHI: ~(C or Z) */ 775 if (!(epsw & (EPSW_FLAG_C | EPSW_FLAG_Z))) 776 goto take_the_loop; 777 return; 778 case 0x6: /* MOV_LCC: ~C */ 779 if (!(epsw & EPSW_FLAG_C)) 780 goto take_the_loop; 781 return; 782 case 0x7: /* MOV_LLS: C or Z */ 783 if (epsw & (EPSW_FLAG_C | EPSW_FLAG_Z)) 784 goto take_the_loop; 785 return; 786 787 case 0x8: /* MOV_LEQ: Z */ 788 if (epsw & EPSW_FLAG_Z) 789 goto take_the_loop; 790 return; 791 case 0x9: /* MOV_LNE: ~Z */ 792 if (!(epsw & EPSW_FLAG_Z)) 793 goto take_the_loop; 794 return; 795 case 0xa: /* MOV_LRA: always */ 796 goto take_the_loop; 797 798 default: 799 BUG(); 800 } 801 802take_the_loop: 803 /* wind the PC back to just after the SETLB insn */ 804 kdebug("loop LAR=%lx", regs->lar); 805 regs->pc = regs->lar - 4; 806} 807 808/* 809 * misalignment handler tests 810 */ 811#ifdef CONFIG_TEST_MISALIGNMENT_HANDLER 812static u8 __initdata testbuf[512] __attribute__((aligned(16))) = { 813 [257] = 0x11, 814 [258] = 0x22, 815 [259] = 0x33, 816 [260] = 0x44, 817}; 818 819#define ASSERTCMP(X, OP, Y) \ 820do { \ 821 if (unlikely(!((X) OP (Y)))) { \ 822 printk(KERN_ERR "\n"); \ 823 printk(KERN_ERR "MISALIGN: Assertion failed at line %u\n", \ 824 __LINE__); \ 825 printk(KERN_ERR "0x%lx " #OP " 0x%lx is false\n", \ 826 (unsigned long)(X), (unsigned long)(Y)); \ 827 BUG(); \ 828 } \ 829} while(0) 830 831static int __init test_misalignment(void) 832{ 833 register void *r asm("e0"); 834 register u32 y asm("e1"); 835 void *p = testbuf, *q; 836 u32 tmp, tmp2, x; 837 838 printk(KERN_NOTICE "==>test_misalignment() [testbuf=%p]\n", p); 839 p++; 840 841 printk(KERN_NOTICE "___ MOV (Am),Dn ___\n"); 842 q = p + 256; 843 asm volatile("mov (%0),%1" : "+a"(q), "=d"(x)); 844 ASSERTCMP(q, ==, p + 256); 845 ASSERTCMP(x, ==, 0x44332211); 846 847 printk(KERN_NOTICE "___ MOV (256,Am),Dn ___\n"); 848 q = p; 849 asm volatile("mov (256,%0),%1" : "+a"(q), "=d"(x)); 850 ASSERTCMP(q, ==, p); 851 ASSERTCMP(x, ==, 0x44332211); 852 853 printk(KERN_NOTICE "___ MOV (Di,Am),Dn ___\n"); 854 tmp = 256; 855 q = p; 856 asm volatile("mov (%2,%0),%1" : "+a"(q), "=d"(x), "+d"(tmp)); 857 ASSERTCMP(q, ==, p); 858 ASSERTCMP(x, ==, 0x44332211); 859 ASSERTCMP(tmp, ==, 256); 860 861 printk(KERN_NOTICE "___ MOV (256,Rm),Rn ___\n"); 862 r = p; 863 asm volatile("mov (256,%0),%1" : "+r"(r), "=r"(y)); 864 ASSERTCMP(r, ==, p); 865 ASSERTCMP(y, ==, 0x44332211); 866 867 printk(KERN_NOTICE "___ MOV (Rm+),Rn ___\n"); 868 r = p + 256; 869 asm volatile("mov (%0+),%1" : "+r"(r), "=r"(y)); 870 ASSERTCMP(r, ==, p + 256 + 4); 871 ASSERTCMP(y, ==, 0x44332211); 872 873 printk(KERN_NOTICE "___ MOV (Rm+,8),Rn ___\n"); 874 r = p + 256; 875 asm volatile("mov (%0+,8),%1" : "+r"(r), "=r"(y)); 876 ASSERTCMP(r, ==, p + 256 + 8); 877 ASSERTCMP(y, ==, 0x44332211); 878 879 printk(KERN_NOTICE "___ MOV (7,SP),Rn ___\n"); 880 asm volatile( 881 "add -16,sp \n" 882 "mov +0x11,%0 \n" 883 "movbu %0,(7,sp) \n" 884 "mov +0x22,%0 \n" 885 "movbu %0,(8,sp) \n" 886 "mov +0x33,%0 \n" 887 "movbu %0,(9,sp) \n" 888 "mov +0x44,%0 \n" 889 "movbu %0,(10,sp) \n" 890 "mov (7,sp),%1 \n" 891 "add +16,sp \n" 892 : "+a"(q), "=d"(x)); 893 ASSERTCMP(x, ==, 0x44332211); 894 895 printk(KERN_NOTICE "___ MOV (259,SP),Rn ___\n"); 896 asm volatile( 897 "add -264,sp \n" 898 "mov +0x11,%0 \n" 899 "movbu %0,(259,sp) \n" 900 "mov +0x22,%0 \n" 901 "movbu %0,(260,sp) \n" 902 "mov +0x33,%0 \n" 903 "movbu %0,(261,sp) \n" 904 "mov +0x55,%0 \n" 905 "movbu %0,(262,sp) \n" 906 "mov (259,sp),%1 \n" 907 "add +264,sp \n" 908 : "+d"(tmp), "=d"(x)); 909 ASSERTCMP(x, ==, 0x55332211); 910 911 printk(KERN_NOTICE "___ MOV (260,SP),Rn ___\n"); 912 asm volatile( 913 "add -264,sp \n" 914 "mov +0x11,%0 \n" 915 "movbu %0,(260,sp) \n" 916 "mov +0x22,%0 \n" 917 "movbu %0,(261,sp) \n" 918 "mov +0x33,%0 \n" 919 "movbu %0,(262,sp) \n" 920 "mov +0x55,%0 \n" 921 "movbu %0,(263,sp) \n" 922 "mov (260,sp),%1 \n" 923 "add +264,sp \n" 924 : "+d"(tmp), "=d"(x)); 925 ASSERTCMP(x, ==, 0x55332211); 926 927 928 printk(KERN_NOTICE "___ MOV_LNE ___\n"); 929 tmp = 1; 930 tmp2 = 2; 931 q = p + 256; 932 asm volatile( 933 "setlb \n" 934 "mov %2,%3 \n" 935 "mov %1,%2 \n" 936 "cmp +0,%1 \n" 937 "mov_lne (%0+,4),%1" 938 : "+r"(q), "+d"(tmp), "+d"(tmp2), "=d"(x) 939 : 940 : "cc"); 941 ASSERTCMP(q, ==, p + 256 + 12); 942 ASSERTCMP(x, ==, 0x44332211); 943 944 printk(KERN_NOTICE "___ MOV in SETLB ___\n"); 945 tmp = 1; 946 tmp2 = 2; 947 q = p + 256; 948 asm volatile( 949 "setlb \n" 950 "mov %1,%3 \n" 951 "mov (%0+),%1 \n" 952 "cmp +0,%1 \n" 953 "lne " 954 : "+a"(q), "+d"(tmp), "+d"(tmp2), "=d"(x) 955 : 956 : "cc"); 957 958 ASSERTCMP(q, ==, p + 256 + 8); 959 ASSERTCMP(x, ==, 0x44332211); 960 961 printk(KERN_NOTICE "<==test_misalignment()\n"); 962 return 0; 963} 964 965arch_initcall(test_misalignment); 966 967#endif /* CONFIG_TEST_MISALIGNMENT_HANDLER */ 968