11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Unaligned memory access handler
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Copyright (C) 2001 Randolph Chung <tausq@debian.org>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Significantly tweaked by LaMont Jones <lamont@debian.org>
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    This program is free software; you can redistribute it and/or modify
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    it under the terms of the GNU General Public License as published by
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    the Free Software Foundation; either version 2, or (at your option)
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    any later version.
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    This program is distributed in the hope that it will be useful,
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    but WITHOUT ANY WARRANTY; without even the implied warranty of
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    GNU General Public License for more details.
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    You should have received a copy of the GNU General Public License
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    along with this program; if not, write to the Free Software
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
23e6fc0449be45a0e7520da6a17a64520743b9aa20Matthew Wilcox#include <linux/jiffies.h>
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
26e6fc0449be45a0e7520da6a17a64520743b9aa20Matthew Wilcox#include <linux/sched.h>
27e6fc0449be45a0e7520da6a17a64520743b9aa20Matthew Wilcox#include <linux/signal.h>
286ee77658ce387ad6c85dcbda4a68bc33efd8de39Akinobu Mita#include <linux/ratelimit.h>
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
30d0c3be806a3fe7f4abdb0f7e7287addb55e73f35Helge Deller#include <asm/hardirq.h>
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* #define DEBUG_UNALIGNED 1 */
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_UNALIGNED
3591bae23ce185b74c9b6dda86b92bb204a1c951c3Harvey Harrison#define DPRINTF(fmt, args...) do { printk(KERN_DEBUG "%s:%d:%s ", __FILE__, __LINE__, __func__ ); printk(KERN_DEBUG fmt, ##args ); } while (0)
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define DPRINTF(fmt, args...)
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
400b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller#ifdef CONFIG_64BIT
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RFMT "%016lx"
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define RFMT "%08lx"
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FIXUP_BRANCH(lbl) \
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"\tldil L%%" #lbl ", %%r1\n"			\
481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"\tldo R%%" #lbl "(%%r1), %%r1\n"		\
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	"\tbv,n %%r0(%%r1)\n"
503fd3a74f45c935f7d6d5c2fb48f06324b18826b7Carlos O'Donell/* If you use FIXUP_BRANCH, then you must list this clobber */
513fd3a74f45c935f7d6d5c2fb48f06324b18826b7Carlos O'Donell#define FIXUP_BRANCH_CLOBBER "r1"
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 1111 1100 0000 0000 0001 0011 1100 0000 */
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE1(a,b,c)	((a)<<26|(b)<<12|(c)<<6)
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE2(a,b)	((a)<<26|(b)<<1)
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE3(a,b)	((a)<<26|(b)<<2)
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE4(a)	((a)<<26)
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE1_MASK	OPCODE1(0x3f,1,0xf)
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE2_MASK 	OPCODE2(0x3f,1)
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE3_MASK	OPCODE3(0x3f,1)
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE4_MASK    OPCODE4(0x3f)
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* skip LDB - never unaligned (index) */
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDH_I	OPCODE1(0x03,0,0x1)
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDW_I	OPCODE1(0x03,0,0x2)
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDD_I	OPCODE1(0x03,0,0x3)
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDDA_I	OPCODE1(0x03,0,0x4)
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDCD_I	OPCODE1(0x03,0,0x5)
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDWA_I	OPCODE1(0x03,0,0x6)
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDCW_I	OPCODE1(0x03,0,0x7)
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* skip LDB - never unaligned (short) */
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDH_S	OPCODE1(0x03,1,0x1)
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDW_S	OPCODE1(0x03,1,0x2)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDD_S	OPCODE1(0x03,1,0x3)
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDDA_S	OPCODE1(0x03,1,0x4)
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDCD_S	OPCODE1(0x03,1,0x5)
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDWA_S	OPCODE1(0x03,1,0x6)
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDCW_S	OPCODE1(0x03,1,0x7)
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* skip STB - never unaligned */
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_STH	OPCODE1(0x03,1,0x9)
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_STW	OPCODE1(0x03,1,0xa)
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_STD	OPCODE1(0x03,1,0xb)
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* skip STBY - never unaligned */
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* skip STDBY - never unaligned */
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_STWA	OPCODE1(0x03,1,0xe)
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_STDA	OPCODE1(0x03,1,0xf)
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FLDWX	OPCODE1(0x09,0,0x0)
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FLDWXR	OPCODE1(0x09,0,0x1)
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FSTWX	OPCODE1(0x09,0,0x8)
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FSTWXR	OPCODE1(0x09,0,0x9)
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FLDWS	OPCODE1(0x09,1,0x0)
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FLDWSR	OPCODE1(0x09,1,0x1)
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FSTWS	OPCODE1(0x09,1,0x8)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FSTWSR	OPCODE1(0x09,1,0x9)
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FLDDX	OPCODE1(0x0b,0,0x0)
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FSTDX	OPCODE1(0x0b,0,0x8)
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FLDDS	OPCODE1(0x0b,1,0x0)
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FSTDS	OPCODE1(0x0b,1,0x8)
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDD_L	OPCODE2(0x14,0)
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FLDD_L	OPCODE2(0x14,1)
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_STD_L	OPCODE2(0x1c,0)
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FSTD_L	OPCODE2(0x1c,1)
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDW_M	OPCODE3(0x17,1)
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FLDW_L	OPCODE3(0x17,0)
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_FSTW_L	OPCODE3(0x1f,0)
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_STW_M	OPCODE3(0x1f,1)
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDH_L    OPCODE4(0x11)
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDW_L    OPCODE4(0x12)
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_LDWM     OPCODE4(0x13)
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_STH_L    OPCODE4(0x19)
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_STW_L    OPCODE4(0x1A)
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define OPCODE_STWM     OPCODE4(0x1B)
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define MAJOR_OP(i) (((i)>>26)&0x3f)
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define R1(i) (((i)>>21)&0x1f)
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define R2(i) (((i)>>16)&0x1f)
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define R3(i) ((i)&0x1f)
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define FR3(i) ((((i)<<1)&0x1f)|(((i)>>6)&1))
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IM(i,n) (((i)>>1&((1<<(n-1))-1))|((i)&1?((0-1L)<<(n-1)):0))
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IM5_2(i) IM((i)>>16,5)
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IM5_3(i) IM((i),5)
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define IM14(i) IM((i),14)
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ERR_NOTHANDLED	-1
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define ERR_PAGEFAULT	-2
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1318039de10aae3cd4cf0ef0ccebd58aff0e8810df2Helge Dellerint unaligned_enabled __read_mostly = 1;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid die_if_kernel (char *str, struct pt_regs *regs, long err);
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int emulate_ldh(struct pt_regs *regs, int toreg)
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long saddr = regs->ior;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long val = 0;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTF("load " RFMT ":" RFMT " to r%d for 2 bytes\n",
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		regs->isr, regs->ior, toreg);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__  (
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsp	%4, %%sr1\n"
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:	ldbs	0(%%sr1,%3), %%r20\n"
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:	ldbs	1(%%sr1,%3), %0\n"
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	depw	%%r20, 23, 24, %0\n"
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	copy	%%r0, %1\n"
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"3:	\n"
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.section .fixup,\"ax\"\n"
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"4:	ldi	-2, %1\n"
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FIXUP_BRANCH(3b)
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.previous\n"
1550b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(1b, 4b)
1560b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(2b, 4b)
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "=r" (val), "=r" (ret)
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "0" (val), "r" (saddr), "r" (regs->isr)
1593fd3a74f45c935f7d6d5c2fb48f06324b18826b7Carlos O'Donell	: "r20", FIXUP_BRANCH_CLOBBER );
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTF("val = 0x" RFMT "\n", val);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (toreg)
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		regs->gr[toreg] = val;
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int emulate_ldw(struct pt_regs *regs, int toreg, int flop)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long saddr = regs->ior;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long val = 0;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTF("load " RFMT ":" RFMT " to r%d for 4 bytes\n",
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		regs->isr, regs->ior, toreg);
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__  (
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	zdep	%3,28,2,%%r19\n"		/* r19=(ofs&3)*8 */
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsp	%4, %%sr1\n"
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	depw	%%r0,31,2,%3\n"
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:	ldw	0(%%sr1,%3),%0\n"
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:	ldw	4(%%sr1,%3),%%r20\n"
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	subi	32,%%r19,%%r19\n"
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtctl	%%r19,11\n"
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	vshd	%0,%%r20,%0\n"
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	copy	%%r0, %1\n"
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"3:	\n"
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.section .fixup,\"ax\"\n"
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"4:	ldi	-2, %1\n"
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FIXUP_BRANCH(3b)
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.previous\n"
1930b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(1b, 4b)
1940b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(2b, 4b)
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "=r" (val), "=r" (ret)
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "0" (val), "r" (saddr), "r" (regs->isr)
1973fd3a74f45c935f7d6d5c2fb48f06324b18826b7Carlos O'Donell	: "r19", "r20", FIXUP_BRANCH_CLOBBER );
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTF("val = 0x" RFMT "\n", val);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flop)
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		((__u32*)(regs->fr))[toreg] = val;
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (toreg)
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		regs->gr[toreg] = val;
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int emulate_ldd(struct pt_regs *regs, int toreg, int flop)
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long saddr = regs->ior;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u64 val = 0;
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTF("load " RFMT ":" RFMT " to r%d for 8 bytes\n",
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		regs->isr, regs->ior, toreg);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PA20
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2180b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller#ifndef CONFIG_64BIT
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!flop)
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__  (
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	depd,z	%3,60,3,%%r19\n"		/* r19=(ofs&7)*8 */
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsp	%4, %%sr1\n"
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	depd	%%r0,63,3,%3\n"
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:	ldd	0(%%sr1,%3),%0\n"
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:	ldd	8(%%sr1,%3),%%r20\n"
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	subi	64,%%r19,%%r19\n"
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsar	%%r19\n"
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	shrpd	%0,%%r20,%%sar,%0\n"
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	copy	%%r0, %1\n"
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"3:	\n"
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.section .fixup,\"ax\"\n"
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"4:	ldi	-2, %1\n"
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FIXUP_BRANCH(3b)
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.previous\n"
2370b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
2380b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "=r" (val), "=r" (ret)
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "0" (val), "r" (saddr), "r" (regs->isr)
2413fd3a74f45c935f7d6d5c2fb48f06324b18826b7Carlos O'Donell	: "r19", "r20", FIXUP_BRANCH_CLOBBER );
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    {
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long valh=0,vall=0;
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__  (
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	zdep	%5,29,2,%%r19\n"		/* r19=(ofs&3)*8 */
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsp	%6, %%sr1\n"
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	dep	%%r0,31,2,%5\n"
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:	ldw	0(%%sr1,%5),%0\n"
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:	ldw	4(%%sr1,%5),%1\n"
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"3:	ldw	8(%%sr1,%5),%%r20\n"
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	subi	32,%%r19,%%r19\n"
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsar	%%r19\n"
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	vshd	%0,%1,%0\n"
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	vshd	%1,%%r20,%1\n"
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	copy	%%r0, %2\n"
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"4:	\n"
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.section .fixup,\"ax\"\n"
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"5:	ldi	-2, %2\n"
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FIXUP_BRANCH(4b)
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.previous\n"
2620b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(1b,5b)
2630b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(2b,5b)
2640b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(3b,5b)
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "=r" (valh), "=r" (vall), "=r" (ret)
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "0" (valh), "1" (vall), "r" (saddr), "r" (regs->isr)
2673fd3a74f45c935f7d6d5c2fb48f06324b18826b7Carlos O'Donell	: "r19", "r20", FIXUP_BRANCH_CLOBBER );
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	val=((__u64)valh<<32)|(__u64)vall;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTF("val = 0x%llx\n", val);
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flop)
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		regs->fr[toreg] = val;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (toreg)
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		regs->gr[toreg] = val;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int emulate_sth(struct pt_regs *regs, int frreg)
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long val = regs->gr[frreg];
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!frreg)
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = 0;
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTF("store r%d (0x" RFMT ") to " RFMT ":" RFMT " for 2 bytes\n", frreg,
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val, regs->isr, regs->ior);
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__ (
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsp %3, %%sr1\n"
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	extrw,u %1, 23, 8, %%r19\n"
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:	stb %1, 1(%%sr1, %2)\n"
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:	stb %%r19, 0(%%sr1, %2)\n"
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	copy	%%r0, %0\n"
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"3:	\n"
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.section .fixup,\"ax\"\n"
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"4:	ldi	-2, %0\n"
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FIXUP_BRANCH(3b)
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.previous\n"
3040b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
3050b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "=r" (ret)
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "r" (val), "r" (regs->ior), "r" (regs->isr)
3083fd3a74f45c935f7d6d5c2fb48f06324b18826b7Carlos O'Donell	: "r19", FIXUP_BRANCH_CLOBBER );
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int emulate_stw(struct pt_regs *regs, int frreg, int flop)
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long val;
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flop)
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = ((__u32*)(regs->fr))[frreg];
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (frreg)
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = regs->gr[frreg];
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = 0;
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTF("store r%d (0x" RFMT ") to " RFMT ":" RFMT " for 4 bytes\n", frreg,
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val, regs->isr, regs->ior);
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__ (
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsp %3, %%sr1\n"
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	zdep	%2, 28, 2, %%r19\n"
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	dep	%%r0, 31, 2, %2\n"
3331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsar	%%r19\n"
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	depwi,z	-2, %%sar, 32, %%r19\n"
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:	ldw	0(%%sr1,%2),%%r20\n"
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:	ldw	4(%%sr1,%2),%%r21\n"
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	vshd	%%r0, %1, %%r22\n"
3381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	vshd	%1, %%r0, %%r1\n"
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	and	%%r20, %%r19, %%r20\n"
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	andcm	%%r21, %%r19, %%r21\n"
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	or	%%r22, %%r20, %%r20\n"
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	or	%%r1, %%r21, %%r21\n"
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	stw	%%r20,0(%%sr1,%2)\n"
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	stw	%%r21,4(%%sr1,%2)\n"
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	copy	%%r0, %0\n"
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"3:	\n"
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.section .fixup,\"ax\"\n"
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"4:	ldi	-2, %0\n"
3491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FIXUP_BRANCH(3b)
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.previous\n"
3510b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(1b,4b)
3520b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(2b,4b)
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "=r" (ret)
3541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "r" (val), "r" (regs->ior), "r" (regs->isr)
3553fd3a74f45c935f7d6d5c2fb48f06324b18826b7Carlos O'Donell	: "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
3561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int emulate_std(struct pt_regs *regs, int frreg, int flop)
3601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__u64 val;
3621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret;
3631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (flop)
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = regs->fr[frreg];
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else if (frreg)
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = regs->gr[frreg];
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	else
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val = 0;
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTF("store r%d (0x%016llx) to " RFMT ":" RFMT " for 8 bytes\n", frreg,
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val,  regs->isr, regs->ior);
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PA20
3750b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller#ifndef CONFIG_64BIT
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!flop)
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -1;
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__ (
3801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsp %3, %%sr1\n"
3811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	depd,z	%2, 60, 3, %%r19\n"
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	depd	%%r0, 63, 3, %2\n"
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsar	%%r19\n"
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	depdi,z	-2, %%sar, 64, %%r19\n"
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:	ldd	0(%%sr1,%2),%%r20\n"
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:	ldd	8(%%sr1,%2),%%r21\n"
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	shrpd	%%r0, %1, %%sar, %%r22\n"
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	shrpd	%1, %%r0, %%sar, %%r1\n"
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	and	%%r20, %%r19, %%r20\n"
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	andcm	%%r21, %%r19, %%r21\n"
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	or	%%r22, %%r20, %%r20\n"
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	or	%%r1, %%r21, %%r21\n"
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"3:	std	%%r20,0(%%sr1,%2)\n"
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"4:	std	%%r21,8(%%sr1,%2)\n"
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	copy	%%r0, %0\n"
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"5:	\n"
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.section .fixup,\"ax\"\n"
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"6:	ldi	-2, %0\n"
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FIXUP_BRANCH(5b)
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.previous\n"
4010b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(1b,6b)
4020b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(2b,6b)
4030b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(3b,6b)
4040b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(4b,6b)
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "=r" (ret)
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "r" (val), "r" (regs->ior), "r" (regs->isr)
4073fd3a74f45c935f7d6d5c2fb48f06324b18826b7Carlos O'Donell	: "r19", "r20", "r21", "r22", "r1", FIXUP_BRANCH_CLOBBER );
4081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
4091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    {
4101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long valh=(val>>32),vall=(val&0xffffffffl);
4111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	__asm__ __volatile__ (
4121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsp	%4, %%sr1\n"
4131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	zdep	%2, 29, 2, %%r19\n"
4141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	dep	%%r0, 31, 2, %2\n"
4151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	mtsar	%%r19\n"
4161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	zvdepi	-2, 32, %%r19\n"
4171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"1:	ldw	0(%%sr1,%3),%%r20\n"
4181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"2:	ldw	8(%%sr1,%3),%%r21\n"
4191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	vshd	%1, %2, %%r1\n"
4201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	vshd	%%r0, %1, %1\n"
4211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	vshd	%2, %%r0, %2\n"
4221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	and	%%r20, %%r19, %%r20\n"
4231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	andcm	%%r21, %%r19, %%r21\n"
4241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	or	%1, %%r20, %1\n"
4251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	or	%2, %%r21, %2\n"
4261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"3:	stw	%1,0(%%sr1,%1)\n"
4271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"4:	stw	%%r1,4(%%sr1,%3)\n"
4281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"5:	stw	%2,8(%%sr1,%3)\n"
4291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	copy	%%r0, %0\n"
4301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"6:	\n"
4311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.section .fixup,\"ax\"\n"
4321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"7:	ldi	-2, %0\n"
4331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	FIXUP_BRANCH(6b)
4341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds"	.previous\n"
4350b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(1b,7b)
4360b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(2b,7b)
4370b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(3b,7b)
4380b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(4b,7b)
4390b3d643f9ead9b5141dedbb2d1b06ce15469fc4aHelge Deller	ASM_EXCEPTIONTABLE_ENTRY(5b,7b)
4401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "=r" (ret)
4411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	: "r" (valh), "r" (vall), "r" (regs->ior), "r" (regs->isr)
4423fd3a74f45c935f7d6d5c2fb48f06324b18826b7Carlos O'Donell	: "r19", "r20", "r21", "r1", FIXUP_BRANCH_CLOBBER );
4431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds    }
4441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return ret;
4471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
4481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid handle_unaligned(struct pt_regs *regs)
4501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
4516ee77658ce387ad6c85dcbda4a68bc33efd8de39Akinobu Mita	static DEFINE_RATELIMIT_STATE(ratelimit, 5 * HZ, 5);
4521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long newbase = R1(regs->iir)?regs->gr[R1(regs->iir)]:0;
4531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int modify = 0;
4541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int ret = ERR_NOTHANDLED;
4551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct siginfo si;
4561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register int flop=0;	/* true if this is a flop */
4571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
458d0c3be806a3fe7f4abdb0f7e7287addb55e73f35Helge Deller	__inc_irq_stat(irq_unaligned_count);
459d0c3be806a3fe7f4abdb0f7e7287addb55e73f35Helge Deller
4601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* log a message with pacing */
461f053725b8985d10c2cc4b837a80a381104c936a4Kyle McMartin	if (user_mode(regs)) {
462f053725b8985d10c2cc4b837a80a381104c936a4Kyle McMartin		if (current->thread.flags & PARISC_UAC_SIGBUS) {
463f053725b8985d10c2cc4b837a80a381104c936a4Kyle McMartin			goto force_sigbus;
464f053725b8985d10c2cc4b837a80a381104c936a4Kyle McMartin		}
465f053725b8985d10c2cc4b837a80a381104c936a4Kyle McMartin
4666ee77658ce387ad6c85dcbda4a68bc33efd8de39Akinobu Mita		if (!(current->thread.flags & PARISC_UAC_NOPRINT) &&
4676ee77658ce387ad6c85dcbda4a68bc33efd8de39Akinobu Mita			__ratelimit(&ratelimit)) {
4681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			char buf[256];
4691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			sprintf(buf, "%s(%d): unaligned access to 0x" RFMT " at ip=0x" RFMT "\n",
47019c5870c0eefd27c6d09d867465e0571262e05d0Alexey Dobriyan				current->comm, task_pid_nr(current), regs->ior, regs->iaoq[0]);
4711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(KERN_WARNING "%s", buf);
4721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef DEBUG_UNALIGNED
4731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			show_regs(regs);
4741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
4751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
476f053725b8985d10c2cc4b837a80a381104c936a4Kyle McMartin
4771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!unaligned_enabled)
4781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			goto force_sigbus;
4791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
4801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* handle modification - OK, it's ugly, see the instruction manual */
4821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (MAJOR_OP(regs->iir))
4831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
4841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x03:
4851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x09:
4861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x0b:
4871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (regs->iir&0x20)
4881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
4891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			modify = 1;
4901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (regs->iir&0x1000)		/* short loads */
4911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (regs->iir&0x200)
4921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					newbase += IM5_3(regs->iir);
4931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				else
4941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					newbase += IM5_2(regs->iir);
4951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			else if (regs->iir&0x2000)	/* scaled indexed */
4961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			{
4971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				int shift=0;
4981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				switch (regs->iir & OPCODE1_MASK)
4991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				{
5001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case OPCODE_LDH_I:
5011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					shift= 1; break;
5021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case OPCODE_LDW_I:
5031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					shift= 2; break;
5041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case OPCODE_LDD_I:
5051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				case OPCODE_LDDA_I:
5061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					shift= 3; break;
5071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
5081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				newbase += (R2(regs->iir)?regs->gr[R2(regs->iir)]:0)<<shift;
5091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else				/* simple indexed */
5101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				newbase += (R2(regs->iir)?regs->gr[R2(regs->iir)]:0);
5111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x13:
5141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x1b:
5151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		modify = 1;
5161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		newbase += IM14(regs->iir);
5171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x14:
5191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x1c:
5201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (regs->iir&8)
5211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
5221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			modify = 1;
5231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			newbase += IM14(regs->iir&~0xe);
5241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x16:
5271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x1e:
5281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		modify = 1;
5291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		newbase += IM14(regs->iir&6);
5301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x17:
5321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case 0x1f:
5331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (regs->iir&4)
5341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
5351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			modify = 1;
5361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			newbase += IM14(regs->iir&~4);
5371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
5381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
5401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* TODO: make this cleaner... */
5421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (regs->iir & OPCODE1_MASK)
5431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
5441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDH_I:
5451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDH_S:
5461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_ldh(regs, R3(regs->iir));
5471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDW_I:
5501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDWA_I:
5511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDW_S:
5521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDWA_S:
5531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_ldw(regs, R3(regs->iir),0);
5541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STH:
5571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_sth(regs, R2(regs->iir));
5581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STW:
5611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STWA:
5621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_stw(regs, R2(regs->iir),0);
5631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PA20
5661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDD_I:
5671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDDA_I:
5681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDD_S:
5691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDDA_S:
5701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_ldd(regs, R3(regs->iir),0);
5711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STD:
5741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STDA:
5751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_std(regs, R2(regs->iir),0);
5761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
5781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FLDWX:
5801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FLDWS:
5811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FLDWXR:
5821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FLDWSR:
5831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flop=1;
5841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_ldw(regs,FR3(regs->iir),1);
5851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FLDDX:
5881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FLDDS:
5891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flop=1;
5901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_ldd(regs,R3(regs->iir),1);
5911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
5921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
5931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FSTWX:
5941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FSTWS:
5951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FSTWXR:
5961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FSTWSR:
5971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flop=1;
5981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_stw(regs,FR3(regs->iir),1);
5991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FSTDX:
6021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FSTDS:
6031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flop=1;
6041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_std(regs,R3(regs->iir),1);
6051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDCD_I:
6081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDCW_I:
6091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDCD_S:
6101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDCW_S:
6111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = ERR_NOTHANDLED;	/* "undefined", but lets kill them. */
6121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PA20
6151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (regs->iir & OPCODE2_MASK)
6161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
6171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FLDD_L:
6181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flop=1;
6191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_ldd(regs,R2(regs->iir),1);
6201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FSTD_L:
6221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flop=1;
6231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_std(regs, R2(regs->iir),1);
6241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDD_L:
6261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_ldd(regs, R2(regs->iir),0);
6271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STD_L:
6291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_std(regs, R2(regs->iir),0);
6301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
6331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (regs->iir & OPCODE3_MASK)
6341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
6351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FLDW_L:
6361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flop=1;
6371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_ldw(regs, R2(regs->iir),0);
6381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDW_M:
6401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_ldw(regs, R2(regs->iir),1);
6411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_FSTW_L:
6441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		flop=1;
6451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_stw(regs, R2(regs->iir),1);
6461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STW_M:
6481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_stw(regs, R2(regs->iir),0);
6491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (regs->iir & OPCODE4_MASK)
6521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
6531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDH_L:
6541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_ldh(regs, R2(regs->iir));
6551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDW_L:
6571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDWM:
6581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_ldw(regs, R2(regs->iir),0);
6591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STH_L:
6611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_sth(regs, R2(regs->iir));
6621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STW_L:
6641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STWM:
6651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		ret = emulate_stw(regs, R2(regs->iir),0);
6661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
6671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
6681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (modify && R1(regs->iir))
6701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		regs->gr[R1(regs->iir)] = newbase;
6711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret == ERR_NOTHANDLED)
6741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "Not-handled unaligned insn 0x%08lx\n", regs->iir);
6751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	DPRINTF("ret = %d\n", ret);
6771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (ret)
6791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	{
6801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		printk(KERN_CRIT "Unaligned handler failed, ret = %d\n", ret);
6811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		die_if_kernel("Unaligned data reference", regs, 28);
6821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
6831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (ret == ERR_PAGEFAULT)
6841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
6851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			si.si_signo = SIGSEGV;
6861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			si.si_errno = 0;
6871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			si.si_code = SEGV_MAPERR;
6881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			si.si_addr = (void __user *)regs->ior;
6891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			force_sig_info(SIGSEGV, &si, current);
6901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
6911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		else
6921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		{
6931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsforce_sigbus:
6941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			/* couldn't handle it ... */
6951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			si.si_signo = SIGBUS;
6961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			si.si_errno = 0;
6971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			si.si_code = BUS_ADRALN;
6981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			si.si_addr = (void __user *)regs->ior;
6991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			force_sig_info(SIGBUS, &si, current);
7001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
7031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* else we handled it, let life go on. */
7061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	regs->gr[0]|=PSW_N;
7071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
7101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * NB: check_unaligned() is only used for PCXS processors right
7111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * now, so we only check for PA1.1 encodings at this point.
7121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
7131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
7151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldscheck_unaligned(struct pt_regs *regs)
7161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
7171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long align_mask;
7181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	/* Get alignment mask */
7201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	align_mask = 0UL;
7221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	switch (regs->iir & OPCODE1_MASK) {
7231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDH_I:
7251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDH_S:
7261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STH:
7271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		align_mask = 1UL;
7281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDW_I:
7311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDWA_I:
7321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDW_S:
7331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_LDWA_S:
7341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STW:
7351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	case OPCODE_STWA:
7361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		align_mask = 3UL;
7371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	default:
7401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		switch (regs->iir & OPCODE4_MASK) {
7411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case OPCODE_LDH_L:
7421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case OPCODE_STH_L:
7431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			align_mask = 1UL;
7441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case OPCODE_LDW_L:
7461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case OPCODE_LDWM:
7471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case OPCODE_STW_L:
7481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		case OPCODE_STWM:
7491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			align_mask = 3UL;
7501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			break;
7511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
7521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		break;
7531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
7541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
7551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return (int)(regs->ior & align_mask);
7561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
7571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
758