xref: /openbmc/linux/arch/xtensa/kernel/align.S (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
15a0015d6SChris Zankel/*
25a0015d6SChris Zankel * arch/xtensa/kernel/align.S
35a0015d6SChris Zankel *
4*a160e941SMax Filippov * Handle unalignment and load/store exceptions.
55a0015d6SChris Zankel *
65a0015d6SChris Zankel * This file is subject to the terms and conditions of the GNU General
75a0015d6SChris Zankel * Public License.  See the file "COPYING" in the main directory of
85a0015d6SChris Zankel * this archive for more details.
95a0015d6SChris Zankel *
105a0015d6SChris Zankel * Copyright (C) 2001 - 2005 Tensilica, Inc.
11c3ef1f4dSMax Filippov * Copyright (C) 2014 Cadence Design Systems Inc.
125a0015d6SChris Zankel *
135a0015d6SChris Zankel * Rewritten by Chris Zankel <chris@zankel.net>
145a0015d6SChris Zankel *
155a0015d6SChris Zankel * Based on work from Joe Taylor <joe@tensilica.com, joetylr@yahoo.com>
165a0015d6SChris Zankel * and Marc Gauthier <marc@tensilica.com, marc@alimni.uwaterloo.ca>
175a0015d6SChris Zankel */
185a0015d6SChris Zankel
195a0015d6SChris Zankel#include <linux/linkage.h>
205a0015d6SChris Zankel#include <asm/current.h>
210013a854SSam Ravnborg#include <asm/asm-offsets.h>
22fbb871e2SMax Filippov#include <asm/asmmacro.h>
235a0015d6SChris Zankel#include <asm/processor.h>
245a0015d6SChris Zankel
25f29cf776SMax Filippov#if XCHAL_UNALIGNED_LOAD_EXCEPTION || defined CONFIG_XTENSA_LOAD_STORE
26f29cf776SMax Filippov#define LOAD_EXCEPTION_HANDLER
27f29cf776SMax Filippov#endif
28f29cf776SMax Filippov
29*a160e941SMax Filippov#if XCHAL_UNALIGNED_STORE_EXCEPTION || defined CONFIG_XTENSA_LOAD_STORE
30*a160e941SMax Filippov#define STORE_EXCEPTION_HANDLER
31*a160e941SMax Filippov#endif
32*a160e941SMax Filippov
33*a160e941SMax Filippov#if defined LOAD_EXCEPTION_HANDLER || defined STORE_EXCEPTION_HANDLER
34f29cf776SMax Filippov#define ANY_EXCEPTION_HANDLER
35f29cf776SMax Filippov#endif
36f29cf776SMax Filippov
37*a160e941SMax Filippov#if XCHAL_HAVE_WINDOWED && defined CONFIG_MMU
38f29cf776SMax Filippov#define UNALIGNED_USER_EXCEPTION
39f29cf776SMax Filippov#endif
405a0015d6SChris Zankel
415a0015d6SChris Zankel/* Big and little endian 16-bit values are located in
425a0015d6SChris Zankel * different halves of a register.  HWORD_START helps to
435a0015d6SChris Zankel * abstract the notion of extracting a 16-bit value from a
445a0015d6SChris Zankel * register.
455a0015d6SChris Zankel * We also have to define new shifting instructions because
465a0015d6SChris Zankel * lsb and msb are on 'opposite' ends in a register for
475a0015d6SChris Zankel * different endian machines.
485a0015d6SChris Zankel *
495a0015d6SChris Zankel * Assume a memory region in ascending address:
505a0015d6SChris Zankel *   	0 1 2 3|4 5 6 7
515a0015d6SChris Zankel *
525a0015d6SChris Zankel * When loading one word into a register, the content of that register is:
535a0015d6SChris Zankel *  LE	3 2 1 0, 7 6 5 4
545a0015d6SChris Zankel *  BE  0 1 2 3, 4 5 6 7
555a0015d6SChris Zankel *
565a0015d6SChris Zankel * Masking the bits of the higher/lower address means:
575a0015d6SChris Zankel *  LE  X X 0 0, 0 0 X X
585a0015d6SChris Zankel *  BE	0 0 X X, X X 0 0
595a0015d6SChris Zankel *
605a0015d6SChris Zankel * Shifting to higher/lower addresses, means:
615a0015d6SChris Zankel *  LE  shift left / shift right
625a0015d6SChris Zankel *  BE  shift right / shift left
635a0015d6SChris Zankel *
645a0015d6SChris Zankel * Extracting 16 bits from a 32 bit reg. value to higher/lower address means:
655a0015d6SChris Zankel *  LE  mask 0 0 X X / shift left
665a0015d6SChris Zankel *  BE  shift left / mask 0 0 X X
675a0015d6SChris Zankel */
685a0015d6SChris Zankel
695a0015d6SChris Zankel#if XCHAL_HAVE_BE
705a0015d6SChris Zankel
715a0015d6SChris Zankel#define HWORD_START	16
725a0015d6SChris Zankel#define	INSN_OP0	28
735a0015d6SChris Zankel#define	INSN_T		24
745a0015d6SChris Zankel#define	INSN_OP1	16
755a0015d6SChris Zankel
765a0015d6SChris Zankel.macro __ssa8r	r;		ssa8l	\r;		.endm
775a0015d6SChris Zankel.macro __sh	r, s;		srl	\r, \s;		.endm
785a0015d6SChris Zankel.macro __sl	r, s;		sll	\r, \s;		.endm
795a0015d6SChris Zankel.macro __exth	r, s;		extui	\r, \s, 0, 16;	.endm
805a0015d6SChris Zankel.macro __extl	r, s;		slli	\r, \s, 16;	.endm
815a0015d6SChris Zankel
825a0015d6SChris Zankel#else
835a0015d6SChris Zankel
845a0015d6SChris Zankel#define HWORD_START	0
855a0015d6SChris Zankel#define	INSN_OP0	0
865a0015d6SChris Zankel#define	INSN_T		4
875a0015d6SChris Zankel#define	INSN_OP1	12
885a0015d6SChris Zankel
895a0015d6SChris Zankel.macro __ssa8r	r;		ssa8b	\r;		.endm
905a0015d6SChris Zankel.macro __sh	r, s;		sll	\r, \s;		.endm
915a0015d6SChris Zankel.macro __sl	r, s;		srl	\r, \s;		.endm
925a0015d6SChris Zankel.macro __exth	r, s;		slli	\r, \s, 16;	.endm
935a0015d6SChris Zankel.macro __extl	r, s;		extui	\r, \s, 0, 16;	.endm
945a0015d6SChris Zankel
955a0015d6SChris Zankel#endif
965a0015d6SChris Zankel
975a0015d6SChris Zankel/*
985a0015d6SChris Zankel *	xxxx xxxx = imm8 field
995a0015d6SChris Zankel *	     yyyy = imm4 field
1005a0015d6SChris Zankel *	     ssss = s field
1015a0015d6SChris Zankel *	     tttt = t field
1025a0015d6SChris Zankel *
1035a0015d6SChris Zankel *	       		 16		    0
1045a0015d6SChris Zankel *		          -------------------
1055a0015d6SChris Zankel *	L32I.N		  yyyy ssss tttt 1000
1065a0015d6SChris Zankel *	S32I.N	          yyyy ssss tttt 1001
1075a0015d6SChris Zankel *
1085a0015d6SChris Zankel *	       23			    0
1095a0015d6SChris Zankel *		-----------------------------
110f29cf776SMax Filippov *	L8UI	xxxx xxxx 0000 ssss tttt 0010
1115a0015d6SChris Zankel *	L16UI	xxxx xxxx 0001 ssss tttt 0010
1125a0015d6SChris Zankel *	L32I	xxxx xxxx 0010 ssss tttt 0010
1135a0015d6SChris Zankel *	XXX	          0011 ssss tttt 0010
1145a0015d6SChris Zankel *	XXX	          0100 ssss tttt 0010
1155a0015d6SChris Zankel *	S16I	xxxx xxxx 0101 ssss tttt 0010
1165a0015d6SChris Zankel *	S32I	xxxx xxxx 0110 ssss tttt 0010
1175a0015d6SChris Zankel *	XXX	          0111 ssss tttt 0010
1185a0015d6SChris Zankel *	XXX	          1000 ssss tttt 0010
1195a0015d6SChris Zankel *	L16SI	xxxx xxxx 1001 ssss tttt 0010
1205a0015d6SChris Zankel *	XXX	          1010           0010
1215a0015d6SChris Zankel *      **L32AI	xxxx xxxx 1011 ssss tttt 0010 unsupported
1225a0015d6SChris Zankel *	XXX	          1100           0010
1235a0015d6SChris Zankel *	XXX	          1101           0010
1245a0015d6SChris Zankel *	XXX	          1110           0010
1255a0015d6SChris Zankel *	**S32RI	xxxx xxxx 1111 ssss tttt 0010 unsupported
1265a0015d6SChris Zankel *		-----------------------------
1275a0015d6SChris Zankel *                           ^         ^    ^
1285a0015d6SChris Zankel *    sub-opcode (NIBBLE_R) -+         |    |
1295a0015d6SChris Zankel *       t field (NIBBLE_T) -----------+    |
1305a0015d6SChris Zankel *  major opcode (NIBBLE_OP0) --------------+
1315a0015d6SChris Zankel */
1325a0015d6SChris Zankel
1335a0015d6SChris Zankel#define OP0_L32I_N	0x8		/* load immediate narrow */
1345a0015d6SChris Zankel#define OP0_S32I_N	0x9		/* store immediate narrow */
135f29cf776SMax Filippov#define OP0_LSAI	0x2		/* load/store */
1365a0015d6SChris Zankel#define OP1_SI_MASK	0x4		/* OP1 bit set for stores */
1375a0015d6SChris Zankel#define OP1_SI_BIT	2		/* OP1 bit number for stores */
1385a0015d6SChris Zankel
139f29cf776SMax Filippov#define OP1_L8UI	0x0
1405a0015d6SChris Zankel#define OP1_L32I	0x2
1415a0015d6SChris Zankel#define OP1_L16UI	0x1
1425a0015d6SChris Zankel#define OP1_L16SI	0x9
1435a0015d6SChris Zankel#define OP1_L32AI	0xb
1445a0015d6SChris Zankel
1455a0015d6SChris Zankel#define OP1_S32I	0x6
1465a0015d6SChris Zankel#define OP1_S16I	0x5
1475a0015d6SChris Zankel#define OP1_S32RI	0xf
1485a0015d6SChris Zankel
1495a0015d6SChris Zankel/*
1505a0015d6SChris Zankel * Entry condition:
1515a0015d6SChris Zankel *
1525a0015d6SChris Zankel *   a0:	trashed, original value saved on stack (PT_AREG0)
1535a0015d6SChris Zankel *   a1:	a1
1545a0015d6SChris Zankel *   a2:	new stack pointer, original in DEPC
15599d5040eSMax Filippov *   a3:	a3
1565a0015d6SChris Zankel *   depc:	a2, original value saved on stack (PT_DEPC)
15799d5040eSMax Filippov *   excsave_1:	dispatch table
1585a0015d6SChris Zankel *
1595a0015d6SChris Zankel *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
1605a0015d6SChris Zankel *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
1615a0015d6SChris Zankel */
1625a0015d6SChris Zankel
163f8f02ca7SMax Filippov	.literal_position
164f29cf776SMax Filippov#ifdef CONFIG_XTENSA_LOAD_STORE
165f29cf776SMax FilippovENTRY(fast_load_store)
166f29cf776SMax Filippov
167f29cf776SMax Filippov	call0	.Lsave_and_load_instruction
168f29cf776SMax Filippov
169f29cf776SMax Filippov	/* Analyze the instruction (load or store?). */
170f29cf776SMax Filippov
171f29cf776SMax Filippov	extui	a0, a4, INSN_OP0, 4	# get insn.op0 nibble
172f29cf776SMax Filippov
173f29cf776SMax Filippov#if XCHAL_HAVE_DENSITY
174f29cf776SMax Filippov	_beqi	a0, OP0_L32I_N, 1f	# L32I.N, jump
175f29cf776SMax Filippov#endif
176f29cf776SMax Filippov	bnei	a0, OP0_LSAI, .Linvalid_instruction
177f29cf776SMax Filippov	/* 'store indicator bit' set, jump */
178f29cf776SMax Filippov	bbsi.l	a4, OP1_SI_BIT + INSN_OP1, .Linvalid_instruction
179f29cf776SMax Filippov
180f29cf776SMax Filippov1:
181f29cf776SMax Filippov	movi	a3, ~3
182f29cf776SMax Filippov	and	a3, a3, a8		# align memory address
183f29cf776SMax Filippov
184f29cf776SMax Filippov	__ssa8	a8
185f29cf776SMax Filippov
186f29cf776SMax Filippov#ifdef CONFIG_MMU
187f29cf776SMax Filippov	/* l32e can't be used here even when it's available. */
188f29cf776SMax Filippov	/* TODO access_ok(a3) could be used here */
189f29cf776SMax Filippov	j	.Linvalid_instruction
190f29cf776SMax Filippov#endif
191f29cf776SMax Filippov	l32i	a5, a3, 0
192f29cf776SMax Filippov	l32i	a6, a3, 4
193f29cf776SMax Filippov	__src_b	a3, a5, a6		# a3 has the data word
194f29cf776SMax Filippov
195f29cf776SMax Filippov#if XCHAL_HAVE_DENSITY
196f29cf776SMax Filippov	addi	a7, a7, 2		# increment PC (assume 16-bit insn)
197f29cf776SMax Filippov	_beqi	a0, OP0_L32I_N, .Lload_w# l32i.n: jump
198f29cf776SMax Filippov	addi	a7, a7, 1
199f29cf776SMax Filippov#else
200f29cf776SMax Filippov	addi	a7, a7, 3
201f29cf776SMax Filippov#endif
202f29cf776SMax Filippov
203f29cf776SMax Filippov	extui	a5, a4, INSN_OP1, 4
204f29cf776SMax Filippov	_beqi	a5, OP1_L32I, .Lload_w
205f29cf776SMax Filippov	bnei	a5, OP1_L8UI, .Lload16
206f29cf776SMax Filippov	extui	a3, a3, 0, 8
207f29cf776SMax Filippov	j	.Lload_w
208f29cf776SMax Filippov
209f29cf776SMax FilippovENDPROC(fast_load_store)
210f29cf776SMax Filippov#endif
211f29cf776SMax Filippov
212f29cf776SMax Filippov/*
213f29cf776SMax Filippov * Entry condition:
214f29cf776SMax Filippov *
215f29cf776SMax Filippov *   a0:	trashed, original value saved on stack (PT_AREG0)
216f29cf776SMax Filippov *   a1:	a1
217f29cf776SMax Filippov *   a2:	new stack pointer, original in DEPC
218f29cf776SMax Filippov *   a3:	a3
219f29cf776SMax Filippov *   depc:	a2, original value saved on stack (PT_DEPC)
220f29cf776SMax Filippov *   excsave_1:	dispatch table
221f29cf776SMax Filippov *
222f29cf776SMax Filippov *   PT_DEPC >= VALID_DOUBLE_EXCEPTION_ADDRESS: double exception, DEPC
223f29cf776SMax Filippov *	     <  VALID_DOUBLE_EXCEPTION_ADDRESS: regular exception
224f29cf776SMax Filippov */
225f29cf776SMax Filippov
226f29cf776SMax Filippov#ifdef ANY_EXCEPTION_HANDLER
2275a0015d6SChris ZankelENTRY(fast_unaligned)
2285a0015d6SChris Zankel
229651d4affSMax Filippov	call0	.Lsave_and_load_instruction
2305a0015d6SChris Zankel
2315a0015d6SChris Zankel	/* Analyze the instruction (load or store?). */
2325a0015d6SChris Zankel
2335a0015d6SChris Zankel	extui	a5, a4, INSN_OP0, 4	# get insn.op0 nibble
2345a0015d6SChris Zankel
235173d6681SChris Zankel#if XCHAL_HAVE_DENSITY
2365a0015d6SChris Zankel	_beqi	a5, OP0_L32I_N, .Lload	# L32I.N, jump
2375a0015d6SChris Zankel	addi	a6, a5, -OP0_S32I_N
2385a0015d6SChris Zankel	_beqz	a6, .Lstore		# S32I.N, do a store
2395a0015d6SChris Zankel#endif
2405a0015d6SChris Zankel	/* 'store indicator bit' not set, jump */
2415a0015d6SChris Zankel	_bbci.l	a4, OP1_SI_BIT + INSN_OP1, .Lload
2425a0015d6SChris Zankel
243*a160e941SMax Filippov#ifdef STORE_EXCEPTION_HANDLER
244f29cf776SMax Filippov
2455a0015d6SChris Zankel	/* Store: Jump to table entry to get the value in the source register.*/
2465a0015d6SChris Zankel
2475a0015d6SChris Zankel.Lstore:movi	a5, .Lstore_table	# table
2485a0015d6SChris Zankel	extui	a6, a4, INSN_T, 4	# get source register
2495a0015d6SChris Zankel	addx8	a5, a6, a5
2505a0015d6SChris Zankel	jx	a5			# jump into table
251f29cf776SMax Filippov#endif
252*a160e941SMax Filippov#ifdef LOAD_EXCEPTION_HANDLER
2535a0015d6SChris Zankel
2545a0015d6SChris Zankel	/* Load: Load memory address. */
2555a0015d6SChris Zankel
2565a0015d6SChris Zankel.Lload: movi	a3, ~3
2575a0015d6SChris Zankel	and	a3, a3, a8		# align memory address
2585a0015d6SChris Zankel
2595a0015d6SChris Zankel	__ssa8	a8
2605a0015d6SChris Zankel#ifdef UNALIGNED_USER_EXCEPTION
2615a0015d6SChris Zankel	addi	a3, a3, 8
2625a0015d6SChris Zankel	l32e	a5, a3, -8
2635a0015d6SChris Zankel	l32e	a6, a3, -4
2645a0015d6SChris Zankel#else
2655a0015d6SChris Zankel	l32i	a5, a3, 0
2665a0015d6SChris Zankel	l32i	a6, a3, 4
2675a0015d6SChris Zankel#endif
2685a0015d6SChris Zankel	__src_b	a3, a5, a6		# a3 has the data word
2695a0015d6SChris Zankel
270173d6681SChris Zankel#if XCHAL_HAVE_DENSITY
2715a0015d6SChris Zankel	addi	a7, a7, 2		# increment PC (assume 16-bit insn)
2725a0015d6SChris Zankel
2735a0015d6SChris Zankel	extui	a5, a4, INSN_OP0, 4
274651d4affSMax Filippov	_beqi	a5, OP0_L32I_N, .Lload_w# l32i.n: jump
2755a0015d6SChris Zankel
2765a0015d6SChris Zankel	addi	a7, a7, 1
2775a0015d6SChris Zankel#else
2785a0015d6SChris Zankel	addi	a7, a7, 3
2795a0015d6SChris Zankel#endif
2805a0015d6SChris Zankel
2815a0015d6SChris Zankel	extui	a5, a4, INSN_OP1, 4
282651d4affSMax Filippov	_beqi	a5, OP1_L32I, .Lload_w	# l32i: jump
283f29cf776SMax Filippov#endif
284f29cf776SMax Filippov#ifdef LOAD_EXCEPTION_HANDLER
285f29cf776SMax Filippov.Lload16:
2865a0015d6SChris Zankel	extui	a3, a3, 0, 16		# extract lower 16 bits
287651d4affSMax Filippov	_beqi	a5, OP1_L16UI, .Lload_w
2885a0015d6SChris Zankel	addi	a5, a5, -OP1_L16SI
289651d4affSMax Filippov	_bnez	a5, .Linvalid_instruction
2905a0015d6SChris Zankel
2915a0015d6SChris Zankel	/* sign extend value */
292651d4affSMax Filippov#if XCHAL_HAVE_SEXT
293651d4affSMax Filippov	sext	a3, a3, 15
294651d4affSMax Filippov#else
2955a0015d6SChris Zankel	slli	a3, a3, 16
2965a0015d6SChris Zankel	srai	a3, a3, 16
297651d4affSMax Filippov#endif
2985a0015d6SChris Zankel
2995a0015d6SChris Zankel	/* Set target register. */
3005a0015d6SChris Zankel
301651d4affSMax Filippov.Lload_w:
3025a0015d6SChris Zankel	extui	a4, a4, INSN_T, 4	# extract target register
3035a0015d6SChris Zankel	movi	a5, .Lload_table
3045a0015d6SChris Zankel	addx8	a4, a4, a5
3055a0015d6SChris Zankel	jx	a4			# jump to entry for target register
3065a0015d6SChris Zankel
3075a0015d6SChris Zankel	.align	8
3085a0015d6SChris Zankel.Lload_table:
3095a0015d6SChris Zankel	s32i	a3, a2, PT_AREG0;	_j .Lexit;	.align 8
3105a0015d6SChris Zankel	mov	a1, a3;			_j .Lexit;	.align 8 # fishy??
3115a0015d6SChris Zankel	s32i	a3, a2, PT_AREG2;	_j .Lexit;	.align 8
3125a0015d6SChris Zankel	s32i	a3, a2, PT_AREG3;	_j .Lexit;	.align 8
3135a0015d6SChris Zankel	s32i	a3, a2, PT_AREG4;	_j .Lexit;	.align 8
3145a0015d6SChris Zankel	s32i	a3, a2, PT_AREG5;	_j .Lexit;	.align 8
3155a0015d6SChris Zankel	s32i	a3, a2, PT_AREG6;	_j .Lexit;	.align 8
3165a0015d6SChris Zankel	s32i	a3, a2, PT_AREG7;	_j .Lexit;	.align 8
3175a0015d6SChris Zankel	s32i	a3, a2, PT_AREG8;	_j .Lexit;	.align 8
3185a0015d6SChris Zankel	mov	a9, a3		;	_j .Lexit;	.align 8
3195a0015d6SChris Zankel	mov	a10, a3		;	_j .Lexit;	.align 8
3205a0015d6SChris Zankel	mov	a11, a3		;	_j .Lexit;	.align 8
3215a0015d6SChris Zankel	mov	a12, a3		;	_j .Lexit;	.align 8
3225a0015d6SChris Zankel	mov	a13, a3		;	_j .Lexit;	.align 8
3235a0015d6SChris Zankel	mov	a14, a3		;	_j .Lexit;	.align 8
3245a0015d6SChris Zankel	mov	a15, a3		;	_j .Lexit;	.align 8
325f29cf776SMax Filippov#endif
326*a160e941SMax Filippov#ifdef STORE_EXCEPTION_HANDLER
3275a0015d6SChris Zankel.Lstore_table:
328651d4affSMax Filippov	l32i	a3, a2, PT_AREG0;	_j .Lstore_w;	.align 8
329651d4affSMax Filippov	mov	a3, a1;			_j .Lstore_w;	.align 8	# fishy??
330651d4affSMax Filippov	l32i	a3, a2, PT_AREG2;	_j .Lstore_w;	.align 8
331651d4affSMax Filippov	l32i	a3, a2, PT_AREG3;	_j .Lstore_w;	.align 8
332651d4affSMax Filippov	l32i	a3, a2, PT_AREG4;	_j .Lstore_w;	.align 8
333651d4affSMax Filippov	l32i	a3, a2, PT_AREG5;	_j .Lstore_w;	.align 8
334651d4affSMax Filippov	l32i	a3, a2, PT_AREG6;	_j .Lstore_w;	.align 8
335651d4affSMax Filippov	l32i	a3, a2, PT_AREG7;	_j .Lstore_w;	.align 8
336651d4affSMax Filippov	l32i	a3, a2, PT_AREG8;	_j .Lstore_w;	.align 8
337651d4affSMax Filippov	mov	a3, a9		;	_j .Lstore_w;	.align 8
338651d4affSMax Filippov	mov	a3, a10		;	_j .Lstore_w;	.align 8
339651d4affSMax Filippov	mov	a3, a11		;	_j .Lstore_w;	.align 8
340651d4affSMax Filippov	mov	a3, a12		;	_j .Lstore_w;	.align 8
341651d4affSMax Filippov	mov	a3, a13		;	_j .Lstore_w;	.align 8
342651d4affSMax Filippov	mov	a3, a14		;	_j .Lstore_w;	.align 8
343651d4affSMax Filippov	mov	a3, a15		;	_j .Lstore_w;	.align 8
344f29cf776SMax Filippov#endif
3455a0015d6SChris Zankel
34621570465SMax Filippov	/* We cannot handle this exception. */
34721570465SMax Filippov
34821570465SMax Filippov	.extern _kernel_exception
349651d4affSMax Filippov.Linvalid_instruction:
35021570465SMax Filippov
35121570465SMax Filippov	movi	a4, 0
35221570465SMax Filippov	rsr	a3, excsave1
35321570465SMax Filippov	s32i	a4, a3, EXC_TABLE_FIXUP
35421570465SMax Filippov
35521570465SMax Filippov	/* Restore a4...a8 and SAR, set SP, and jump to default exception. */
35621570465SMax Filippov
357651d4affSMax Filippov	l32i	a0, a2, PT_SAR
35821570465SMax Filippov	l32i	a8, a2, PT_AREG8
35921570465SMax Filippov	l32i	a7, a2, PT_AREG7
36021570465SMax Filippov	l32i	a6, a2, PT_AREG6
36121570465SMax Filippov	l32i	a5, a2, PT_AREG5
36221570465SMax Filippov	l32i	a4, a2, PT_AREG4
36321570465SMax Filippov	wsr	a0, sar
36421570465SMax Filippov	mov	a1, a2
36521570465SMax Filippov
36621570465SMax Filippov	rsr	a0, ps
36721570465SMax Filippov	bbsi.l  a0, PS_UM_BIT, 2f     # jump if user mode
36821570465SMax Filippov
36921570465SMax Filippov	movi	a0, _kernel_exception
37021570465SMax Filippov	jx	a0
37121570465SMax Filippov
37221570465SMax Filippov2:	movi	a0, _user_exception
37321570465SMax Filippov	jx	a0
374*a160e941SMax Filippov
375*a160e941SMax Filippov#ifdef STORE_EXCEPTION_HANDLER
37621570465SMax Filippov
377651d4affSMax Filippov	# a7: instruction pointer, a4: instruction, a3: value
378651d4affSMax Filippov.Lstore_w:
3795a0015d6SChris Zankel	movi	a6, 0			# mask: ffffffff:00000000
3805a0015d6SChris Zankel
381173d6681SChris Zankel#if XCHAL_HAVE_DENSITY
3825a0015d6SChris Zankel	addi	a7, a7, 2		# incr. PC,assume 16-bit instruction
3835a0015d6SChris Zankel
3845a0015d6SChris Zankel	extui	a5, a4, INSN_OP0, 4	# extract OP0
3855a0015d6SChris Zankel	addi	a5, a5, -OP0_S32I_N
3865a0015d6SChris Zankel	_beqz	a5, 1f			# s32i.n: jump
3875a0015d6SChris Zankel
3885a0015d6SChris Zankel	addi	a7, a7, 1		# increment PC, 32-bit instruction
3895a0015d6SChris Zankel#else
3905a0015d6SChris Zankel	addi	a7, a7, 3		# increment PC, 32-bit instruction
3915a0015d6SChris Zankel#endif
3925a0015d6SChris Zankel
3935a0015d6SChris Zankel	extui	a5, a4, INSN_OP1, 4	# extract OP1
3945a0015d6SChris Zankel	_beqi	a5, OP1_S32I, 1f	# jump if 32 bit store
395651d4affSMax Filippov	_bnei	a5, OP1_S16I, .Linvalid_instruction
3965a0015d6SChris Zankel
3975a0015d6SChris Zankel	movi	a5, -1
3985a0015d6SChris Zankel	__extl	a3, a3			# get 16-bit value
3995a0015d6SChris Zankel	__exth	a6, a5			# get 16-bit mask ffffffff:ffff0000
4005a0015d6SChris Zankel
4015a0015d6SChris Zankel	/* Get memory address */
4025a0015d6SChris Zankel
4035a0015d6SChris Zankel1:
4045a0015d6SChris Zankel	movi	a4, ~3
4055a0015d6SChris Zankel	and	a4, a4, a8		# align memory address
4065a0015d6SChris Zankel
4075a0015d6SChris Zankel	/* Insert value into memory */
4085a0015d6SChris Zankel
4095a0015d6SChris Zankel	movi	a5, -1			# mask: ffffffff:XXXX0000
4105a0015d6SChris Zankel#ifdef UNALIGNED_USER_EXCEPTION
4115a0015d6SChris Zankel	addi	a4, a4, 8
4125a0015d6SChris Zankel#endif
4135a0015d6SChris Zankel
4145a0015d6SChris Zankel	__ssa8r a8
415e9500dd8SMax Filippov	__src_b	a8, a5, a6		# lo-mask  F..F0..0 (BE) 0..0F..F (LE)
4165a0015d6SChris Zankel	__src_b	a6, a6, a5		# hi-mask  0..0F..F (BE) F..F0..0 (LE)
4175a0015d6SChris Zankel#ifdef UNALIGNED_USER_EXCEPTION
4185a0015d6SChris Zankel	l32e	a5, a4, -8
4195a0015d6SChris Zankel#else
4205a0015d6SChris Zankel	l32i	a5, a4, 0		# load lower address word
4215a0015d6SChris Zankel#endif
422e9500dd8SMax Filippov	and	a5, a5, a8		# mask
423e9500dd8SMax Filippov	__sh	a8, a3 			# shift value
424e9500dd8SMax Filippov	or	a5, a5, a8		# or with original value
4255a0015d6SChris Zankel#ifdef UNALIGNED_USER_EXCEPTION
4265a0015d6SChris Zankel	s32e	a5, a4, -8
427e9500dd8SMax Filippov	l32e	a8, a4, -4
4285a0015d6SChris Zankel#else
4295a0015d6SChris Zankel	s32i	a5, a4, 0		# store
430e9500dd8SMax Filippov	l32i	a8, a4, 4		# same for upper address word
4315a0015d6SChris Zankel#endif
4325a0015d6SChris Zankel	__sl	a5, a3
433e9500dd8SMax Filippov	and	a6, a8, a6
4345a0015d6SChris Zankel	or	a6, a6, a5
4355a0015d6SChris Zankel#ifdef UNALIGNED_USER_EXCEPTION
4365a0015d6SChris Zankel	s32e	a6, a4, -4
4375a0015d6SChris Zankel#else
4385a0015d6SChris Zankel	s32i	a6, a4, 4
4395a0015d6SChris Zankel#endif
440f29cf776SMax Filippov#endif
441*a160e941SMax Filippov
4425a0015d6SChris Zankel.Lexit:
443e9500dd8SMax Filippov#if XCHAL_HAVE_LOOPS
444e9500dd8SMax Filippov	rsr	a4, lend		# check if we reached LEND
445e9500dd8SMax Filippov	bne	a7, a4, 1f
446e9500dd8SMax Filippov	rsr	a4, lcount		# and LCOUNT != 0
447e9500dd8SMax Filippov	beqz	a4, 1f
448e9500dd8SMax Filippov	addi	a4, a4, -1		# decrement LCOUNT and set
449e9500dd8SMax Filippov	rsr	a7, lbeg		# set PC to LBEGIN
450e9500dd8SMax Filippov	wsr	a4, lcount
451e9500dd8SMax Filippov#endif
452e9500dd8SMax Filippov
453e9500dd8SMax Filippov1:	wsr	a7, epc1		# skip emulated instruction
454e9500dd8SMax Filippov
455a83b02e9SMax Filippov	/* Update icount if we're single-stepping in userspace. */
456a83b02e9SMax Filippov	rsr	a4, icountlevel
457a83b02e9SMax Filippov	beqz	a4, 1f
458a83b02e9SMax Filippov	bgeui	a4, LOCKLEVEL + 1, 1f
459a83b02e9SMax Filippov	rsr	a4, icount
460a83b02e9SMax Filippov	addi	a4, a4, 1
461a83b02e9SMax Filippov	wsr	a4, icount
462a83b02e9SMax Filippov1:
4635a0015d6SChris Zankel	movi	a4, 0
464bc5378fcSMax Filippov	rsr	a3, excsave1
4655a0015d6SChris Zankel	s32i	a4, a3, EXC_TABLE_FIXUP
4665a0015d6SChris Zankel
4675a0015d6SChris Zankel	/* Restore working register */
4685a0015d6SChris Zankel
469651d4affSMax Filippov	l32i	a0, a2, PT_SAR
470173d6681SChris Zankel	l32i	a8, a2, PT_AREG8
4715a0015d6SChris Zankel	l32i	a7, a2, PT_AREG7
4725a0015d6SChris Zankel	l32i	a6, a2, PT_AREG6
4735a0015d6SChris Zankel	l32i	a5, a2, PT_AREG5
4745a0015d6SChris Zankel	l32i	a4, a2, PT_AREG4
4755a0015d6SChris Zankel	l32i	a3, a2, PT_AREG3
4765a0015d6SChris Zankel
4775a0015d6SChris Zankel	/* restore SAR and return */
4785a0015d6SChris Zankel
479bc5378fcSMax Filippov	wsr	a0, sar
4805a0015d6SChris Zankel	l32i	a0, a2, PT_AREG0
4815a0015d6SChris Zankel	l32i	a2, a2, PT_AREG2
4825a0015d6SChris Zankel	rfe
4835a0015d6SChris Zankel
484651d4affSMax Filippov	.align	4
485651d4affSMax Filippov.Lsave_and_load_instruction:
486651d4affSMax Filippov
487651d4affSMax Filippov	/* Save some working register */
488651d4affSMax Filippov
489651d4affSMax Filippov	s32i	a3, a2, PT_AREG3
490651d4affSMax Filippov	s32i	a4, a2, PT_AREG4
491651d4affSMax Filippov	s32i	a5, a2, PT_AREG5
492651d4affSMax Filippov	s32i	a6, a2, PT_AREG6
493651d4affSMax Filippov	s32i	a7, a2, PT_AREG7
494651d4affSMax Filippov	s32i	a8, a2, PT_AREG8
495651d4affSMax Filippov
496651d4affSMax Filippov	rsr	a4, depc
497651d4affSMax Filippov	s32i	a4, a2, PT_AREG2
498651d4affSMax Filippov
499651d4affSMax Filippov	rsr	a5, sar
500651d4affSMax Filippov	s32i	a5, a2, PT_SAR
501651d4affSMax Filippov
502651d4affSMax Filippov	rsr	a3, excsave1
503651d4affSMax Filippov	movi	a4, fast_unaligned_fixup
504651d4affSMax Filippov	s32i	a4, a3, EXC_TABLE_FIXUP
505651d4affSMax Filippov
506651d4affSMax Filippov	rsr	a8, excvaddr		# load unaligned memory address
507651d4affSMax Filippov
508651d4affSMax Filippov	/* Now, identify one of the following load/store instructions.
509651d4affSMax Filippov	 *
510651d4affSMax Filippov	 * The only possible danger of a double exception on the
511651d4affSMax Filippov	 * following l32i instructions is kernel code in vmalloc
512651d4affSMax Filippov	 * memory. The processor was just executing at the EPC_1
513651d4affSMax Filippov	 * address, and indeed, already fetched the instruction.  That
514651d4affSMax Filippov	 * guarantees a TLB mapping, which hasn't been replaced by
515651d4affSMax Filippov	 * this unaligned exception handler that uses only static TLB
516651d4affSMax Filippov	 * mappings. However, high-level interrupt handlers might
517651d4affSMax Filippov	 * modify TLB entries, so for the generic case, we register a
518651d4affSMax Filippov	 * TABLE_FIXUP handler here, too.
519651d4affSMax Filippov	 */
520651d4affSMax Filippov
521651d4affSMax Filippov	/* a3...a6 saved on stack, a2 = SP */
522651d4affSMax Filippov
523651d4affSMax Filippov	/* Extract the instruction that caused the unaligned access. */
524651d4affSMax Filippov
525651d4affSMax Filippov	rsr	a7, epc1	# load exception address
526651d4affSMax Filippov	movi	a3, ~3
527651d4affSMax Filippov	and	a3, a3, a7	# mask lower bits
528651d4affSMax Filippov
529651d4affSMax Filippov	l32i	a4, a3, 0	# load 2 words
530651d4affSMax Filippov	l32i	a5, a3, 4
531651d4affSMax Filippov
532651d4affSMax Filippov	__ssa8	a7
533651d4affSMax Filippov	__src_b	a4, a4, a5	# a4 has the instruction
534651d4affSMax Filippov
535651d4affSMax Filippov	ret
536*a160e941SMax Filippov
537d1538c46SChris ZankelENDPROC(fast_unaligned)
5385a0015d6SChris Zankel
539c3ef1f4dSMax FilippovENTRY(fast_unaligned_fixup)
540c3ef1f4dSMax Filippov
541c3ef1f4dSMax Filippov	l32i	a2, a3, EXC_TABLE_DOUBLE_SAVE
542c3ef1f4dSMax Filippov	wsr	a3, excsave1
543c3ef1f4dSMax Filippov
544c3ef1f4dSMax Filippov	l32i	a8, a2, PT_AREG8
545c3ef1f4dSMax Filippov	l32i	a7, a2, PT_AREG7
546c3ef1f4dSMax Filippov	l32i	a6, a2, PT_AREG6
547c3ef1f4dSMax Filippov	l32i	a5, a2, PT_AREG5
548651d4affSMax Filippov	l32i	a4, a2, PT_SAR
549c3ef1f4dSMax Filippov	l32i	a0, a2, PT_AREG2
550651d4affSMax Filippov	wsr	a4, sar
551651d4affSMax Filippov	wsr	a0, depc			# restore depc and a0
552651d4affSMax Filippov	l32i	a4, a2, PT_AREG4
553c3ef1f4dSMax Filippov
554c3ef1f4dSMax Filippov	rsr	a0, exccause
555c3ef1f4dSMax Filippov	s32i	a0, a2, PT_DEPC			# mark as a regular exception
556c3ef1f4dSMax Filippov
557c3ef1f4dSMax Filippov	rsr	a0, ps
558c3ef1f4dSMax Filippov	bbsi.l  a0, PS_UM_BIT, 1f		# jump if user mode
559c3ef1f4dSMax Filippov
560c3ef1f4dSMax Filippov	rsr	a0, exccause
561c3ef1f4dSMax Filippov	addx4	a0, a0, a3              	# find entry in table
562c3ef1f4dSMax Filippov	l32i	a0, a0, EXC_TABLE_FAST_KERNEL   # load handler
563c3ef1f4dSMax Filippov	l32i	a3, a2, PT_AREG3
564c3ef1f4dSMax Filippov	jx	a0
565c3ef1f4dSMax Filippov1:
566c3ef1f4dSMax Filippov	rsr	a0, exccause
567c3ef1f4dSMax Filippov	addx4	a0, a0, a3              	# find entry in table
568c3ef1f4dSMax Filippov	l32i	a0, a0, EXC_TABLE_FAST_USER     # load handler
569c3ef1f4dSMax Filippov	l32i	a3, a2, PT_AREG3
570c3ef1f4dSMax Filippov	jx	a0
571c3ef1f4dSMax Filippov
572c3ef1f4dSMax FilippovENDPROC(fast_unaligned_fixup)
573f29cf776SMax Filippov#endif
574