1/* SPDX-License-Identifier: GPL-2.0-only */
2/*
3 * linux/arch/unicore32/kernel/entry.S
4 *
5 * Code specific to PKUnity SoC and UniCore ISA
6 *
7 * Copyright (C) 2001-2010 GUAN Xue-tao
8 *
9 *  Low-level vector interface routines
10 */
11#include <linux/init.h>
12#include <linux/linkage.h>
13#include <asm/assembler.h>
14#include <asm/errno.h>
15#include <asm/thread_info.h>
16#include <asm/memory.h>
17#include <asm/unistd.h>
18#include <generated/asm-offsets.h>
19#include "debug-macro.S"
20
21@
22@ Most of the stack format comes from struct pt_regs, but with
23@ the addition of 8 bytes for storing syscall args 5 and 6.
24@
25#define S_OFF		8
26
27/*
28 * The SWI code relies on the fact that R0 is at the bottom of the stack
29 * (due to slow/fast restore user regs).
30 */
31#if S_R0 != 0
32#error "Please fix"
33#endif
34
35	.macro	zero_fp
36#ifdef CONFIG_FRAME_POINTER
37	mov	fp, #0
38#endif
39	.endm
40
41	.macro	alignment_trap, rtemp
42#ifdef CONFIG_ALIGNMENT_TRAP
43	ldw	\rtemp, .LCcralign
44	ldw	\rtemp, [\rtemp]
45	movc	p0.c1, \rtemp, #0
46#endif
47	.endm
48
49	.macro	load_user_sp_lr, rd, rtemp, offset = 0
50	mov	\rtemp, asr
51	xor	\rtemp, \rtemp, #(PRIV_MODE ^ SUSR_MODE)
52	mov.a	asr, \rtemp			@ switch to the SUSR mode
53
54	ldw	sp, [\rd+], #\offset		@ load sp_user
55	ldw	lr, [\rd+], #\offset + 4	@ load lr_user
56
57	xor	\rtemp, \rtemp, #(PRIV_MODE ^ SUSR_MODE)
58	mov.a	asr, \rtemp			@ switch back to the PRIV mode
59	.endm
60
61	.macro	priv_exit, rpsr
62	mov.a	bsr, \rpsr
63	ldm.w	(r0 - r15), [sp]+
64	ldm.b	(r16 - pc), [sp]+		@ load r0 - pc, asr
65	.endm
66
67	.macro	restore_user_regs, fast = 0, offset = 0
68	ldw	r1, [sp+], #\offset + S_PSR	@ get calling asr
69	ldw	lr, [sp+], #\offset + S_PC	@ get pc
70	mov.a	bsr, r1				@ save in bsr_priv
71	.if	\fast
72	add	sp, sp, #\offset + S_R1		@ r0 is syscall return value
73	ldm.w	(r1 - r15), [sp]+		@ get calling r1 - r15
74	ldur	(r16 - lr), [sp]+		@ get calling r16 - lr
75	.else
76	ldm.w	(r0 - r15), [sp]+		@ get calling r0 - r15
77	ldur	(r16 - lr), [sp]+		@ get calling r16 - lr
78	.endif
79	nop
80	add	sp, sp, #S_FRAME_SIZE - S_R16
81	mov.a	pc, lr				@ return
82						@ and move bsr_priv into asr
83	.endm
84
85	.macro	get_thread_info, rd
86	mov	\rd, sp >> #13
87	mov	\rd, \rd << #13
88	.endm
89
90	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
91	ldw	\base, =(PKUNITY_INTC_BASE)
92	ldw	\irqstat, [\base+], #0xC	@ INTC_ICIP
93	ldw	\tmp,	  [\base+], #0x4	@ INTC_ICMR
94	and.a	\irqstat, \irqstat, \tmp
95	beq	1001f
96	cntlz	\irqnr, \irqstat
97	rsub	\irqnr, \irqnr, #31
981001:	/* EQ will be set if no irqs pending */
99	.endm
100
101#ifdef CONFIG_DEBUG_LL
102	.macro	printreg, reg, temp
103		adr	\temp, 901f
104		stm	(r0-r3), [\temp]+
105		stw	lr, [\temp+], #0x10
106		mov	r0, \reg
107		b.l	printhex8
108		mov	r0, #':'
109		b.l	printch
110		mov	r0, pc
111		b.l	printhex8
112		adr	r0, 902f
113		b.l	printascii
114		adr	\temp, 901f
115		ldm	(r0-r3), [\temp]+
116		ldw	lr, [\temp+], #0x10
117		b	903f
118901:	.word	0, 0, 0, 0, 0	@ r0-r3, lr
119902:	.asciz	": epip4d\n"
120	.align
121903:
122	.endm
123#endif
124
125/*
126 * These are the registers used in the syscall handler, and allow us to
127 * have in theory up to 7 arguments to a function - r0 to r6.
128 *
129 * Note that tbl == why is intentional.
130 *
131 * We must set at least "tsk" and "why" when calling ret_with_reschedule.
132 */
133scno	.req	r21		@ syscall number
134tbl	.req	r22		@ syscall table pointer
135why	.req	r22		@ Linux syscall (!= 0)
136tsk	.req	r23		@ current thread_info
137
138/*
139 * Interrupt handling.  Preserves r17, r18, r19
140 */
141	.macro	intr_handler
1421:	get_irqnr_and_base r0, r6, r5, lr
143	beq	2f
144	mov	r1, sp
145	@
146	@ routine called with r0 = irq number, r1 = struct pt_regs *
147	@
148	adr	lr, 1b
149	b	asm_do_IRQ
1502:
151	.endm
152
153/*
154 * PRIV mode handlers
155 */
156	.macro	priv_entry
157	sub	sp, sp, #(S_FRAME_SIZE - 4)
158	stm	(r1 - r15), [sp]+
159	add	r5, sp, #S_R15
160	stm	(r16 - r28), [r5]+
161
162	ldm	(r1 - r3), [r0]+
163	add	r5, sp, #S_SP - 4	@ here for interlock avoidance
164	mov	r4, #-1			@  ""  ""      ""       ""
165	add	r0, sp, #(S_FRAME_SIZE - 4)
166	stw.w	r1, [sp+], #-4		@ save the "real" r0 copied
167					@ from the exception stack
168
169	mov	r1, lr
170
171	@
172	@ We are now ready to fill in the remaining blanks on the stack:
173	@
174	@  r0 - sp_priv
175	@  r1 - lr_priv
176	@  r2 - lr_<exception>, already fixed up for correct return/restart
177	@  r3 - bsr_<exception>
178	@  r4 - orig_r0 (see pt_regs definition in ptrace.h)
179	@
180	stm	(r0 - r4), [r5]+
181	.endm
182
183/*
184 * User mode handlers
185 *
186 */
187	.macro	user_entry
188	sub	sp, sp, #S_FRAME_SIZE
189	stm	(r1 - r15), [sp+]
190	add	r4, sp, #S_R16
191	stm	(r16 - r28), [r4]+
192
193	ldm	(r1 - r3), [r0]+
194	add	r0, sp, #S_PC		@ here for interlock avoidance
195	mov	r4, #-1			@  ""  ""     ""        ""
196
197	stw	r1, [sp]		@ save the "real" r0 copied
198					@ from the exception stack
199
200	@
201	@ We are now ready to fill in the remaining blanks on the stack:
202	@
203	@  r2 - lr_<exception>, already fixed up for correct return/restart
204	@  r3 - bsr_<exception>
205	@  r4 - orig_r0 (see pt_regs definition in ptrace.h)
206	@
207	@ Also, separately save sp_user and lr_user
208	@
209	stm	(r2 - r4), [r0]+
210	stur	(sp, lr), [r0-]
211
212	@
213	@ Enable the alignment trap while in kernel mode
214	@
215	alignment_trap r0
216
217	@
218	@ Clear FP to mark the first stack frame
219	@
220	zero_fp
221	.endm
222
223	.text
224
225@
226@ __invalid - generic code for failed exception
227@			(re-entrant version of handlers)
228@
229__invalid:
230	sub	sp, sp, #S_FRAME_SIZE
231	stm	(r1 - r15), [sp+]
232	add	r1, sp, #S_R16
233	stm	(r16 - r28, sp, lr), [r1]+
234
235	zero_fp
236
237	ldm	(r4 - r6), [r0]+
238	add	r0, sp, #S_PC		@ here for interlock avoidance
239	mov	r7, #-1			@  ""   ""    ""        ""
240	stw	r4, [sp]		@ save preserved r0
241	stm	(r5 - r7), [r0]+	@ lr_<exception>,
242					@ asr_<exception>, "old_r0"
243
244	mov	r0, sp
245	mov	r1, asr
246	b	bad_mode
247ENDPROC(__invalid)
248
249	.align	5
250__dabt_priv:
251	priv_entry
252
253	@
254	@ get ready to re-enable interrupts if appropriate
255	@
256	mov	r17, asr
257	cand.a	r3, #PSR_I_BIT
258	bne	1f
259	andn	r17, r17, #PSR_I_BIT
2601:
261
262	@
263	@ Call the processor-specific abort handler:
264	@
265	@  r2 - aborted context pc
266	@  r3 - aborted context asr
267	@
268	@ The abort handler must return the aborted address in r0, and
269	@ the fault status register in r1.
270	@
271	movc	r1, p0.c3, #0		@ get FSR
272	movc	r0, p0.c4, #0		@ get FAR
273
274	@
275	@ set desired INTR state, then call main handler
276	@
277	mov.a	asr, r17
278	mov	r2, sp
279	b.l	do_DataAbort
280
281	@
282	@ INTRs off again before pulling preserved data off the stack
283	@
284	disable_irq r0
285
286	@
287	@ restore BSR and restart the instruction
288	@
289	ldw	r2, [sp+], #S_PSR
290	priv_exit r2				@ return from exception
291ENDPROC(__dabt_priv)
292
293	.align	5
294__intr_priv:
295	priv_entry
296
297	intr_handler
298
299	mov	r0, #0				@ epip4d
300	movc	p0.c5, r0, #14
301	nop; nop; nop; nop; nop; nop; nop; nop
302
303	ldw	r4, [sp+], #S_PSR		@ irqs are already disabled
304
305	priv_exit r4				@ return from exception
306ENDPROC(__intr_priv)
307
308	.ltorg
309
310	.align	5
311__extn_priv:
312	priv_entry
313
314	mov	r0, sp				@ struct pt_regs *regs
315	mov	r1, asr
316	b	bad_mode			@ not supported
317ENDPROC(__extn_priv)
318
319	.align	5
320__pabt_priv:
321	priv_entry
322
323	@
324	@ re-enable interrupts if appropriate
325	@
326	mov	r17, asr
327	cand.a	r3, #PSR_I_BIT
328	bne	1f
329	andn	r17, r17, #PSR_I_BIT
3301:
331
332	@
333	@ set args, then call main handler
334	@
335	@  r0 - address of faulting instruction
336	@  r1 - pointer to registers on stack
337	@
338	mov	r0, r2			@ pass address of aborted instruction
339	mov	r1, #5
340	mov.a	asr, r17
341	mov	r2, sp			@ regs
342	b.l	do_PrefetchAbort	@ call abort handler
343
344	@
345	@ INTRs off again before pulling preserved data off the stack
346	@
347	disable_irq r0
348
349	@
350	@ restore BSR and restart the instruction
351	@
352	ldw	r2, [sp+], #S_PSR
353	priv_exit r2			@ return from exception
354ENDPROC(__pabt_priv)
355
356	.align	5
357.LCcralign:
358	.word	cr_alignment
359
360	.align	5
361__dabt_user:
362	user_entry
363
364#ifdef CONFIG_UNICORE_FPU_F64
365	cff	ip, s31
366	cand.a	ip, #0x08000000		@ FPU execption traps?
367	beq	209f
368
369	ldw	ip, [sp+], #S_PC
370	add	ip, ip, #4
371	stw	ip, [sp+], #S_PC
372	@
373	@ fall through to the emulation code, which returns using r19 if
374	@ it has emulated the instruction, or the more conventional lr
375	@ if we are to treat this as a real extended instruction
376	@
377	@  r0 - instruction
378	@
3791:	ldw.u	r0, [r2]
380	adr	r19, ret_from_exception
381	adr	lr, 209f
382	@
383	@ fallthrough to call do_uc_f64
384	@
385/*
386 * Check whether the instruction is a co-processor instruction.
387 * If yes, we need to call the relevant co-processor handler.
388 *
389 * Note that we don't do a full check here for the co-processor
390 * instructions; all instructions with bit 27 set are well
391 * defined.  The only instructions that should fault are the
392 * co-processor instructions.
393 *
394 * Emulators may wish to make use of the following registers:
395 *  r0  = instruction opcode.
396 *  r2  = PC
397 *  r19 = normal "successful" return address
398 *  r20 = this threads thread_info structure.
399 *  lr  = unrecognised instruction return address
400 */
401	get_thread_info r20			@ get current thread
402	and	r8, r0, #0x00003c00		@ mask out CP number
403	mov	r7, #1
404	stb	r7, [r20+], #TI_USED_CP + 2	@ set appropriate used_cp[]
405
406	@ F64 hardware support entry point.
407	@  r0  = faulted instruction
408	@  r19 = return address
409	@  r20 = fp_state
410	enable_irq r4
411	add	r20, r20, #TI_FPSTATE	@ r20 = workspace
412	cff	r1, s31			@ get fpu FPSCR
413	andn    r2, r1, #0x08000000
414	ctf     r2, s31			@ clear 27 bit
415	mov	r2, sp			@ nothing stacked - regdump is at TOS
416	mov	lr, r19			@ setup for a return to the user code
417
418	@ Now call the C code to package up the bounce to the support code
419	@   r0 holds the trigger instruction
420	@   r1 holds the FPSCR value
421	@   r2 pointer to register dump
422	b	ucf64_exchandler
423209:
424#endif
425	@
426	@ Call the processor-specific abort handler:
427	@
428	@  r2 - aborted context pc
429	@  r3 - aborted context asr
430	@
431	@ The abort handler must return the aborted address in r0, and
432	@ the fault status register in r1.
433	@
434	movc	r1, p0.c3, #0		@ get FSR
435	movc	r0, p0.c4, #0		@ get FAR
436
437	@
438	@ INTRs on, then call the main handler
439	@
440	enable_irq r2
441	mov	r2, sp
442	adr	lr, ret_from_exception
443	b	do_DataAbort
444ENDPROC(__dabt_user)
445
446	.align	5
447__intr_user:
448	user_entry
449
450	get_thread_info tsk
451
452	intr_handler
453
454	mov	why, #0
455	b	ret_to_user
456ENDPROC(__intr_user)
457
458	.ltorg
459
460	.align	5
461__extn_user:
462	user_entry
463
464	mov	r0, sp
465	mov	r1, asr
466	b	bad_mode
467ENDPROC(__extn_user)
468
469	.align	5
470__pabt_user:
471	user_entry
472
473	mov	r0, r2			@ pass address of aborted instruction.
474	mov	r1, #5
475	enable_irq r1			@ Enable interrupts
476	mov	r2, sp			@ regs
477	b.l	do_PrefetchAbort	@ call abort handler
478	/* fall through */
479/*
480 * This is the return code to user mode for abort handlers
481 */
482ENTRY(ret_from_exception)
483	get_thread_info tsk
484	mov	why, #0
485	b	ret_to_user
486ENDPROC(__pabt_user)
487ENDPROC(ret_from_exception)
488
489/*
490 * Register switch for UniCore V2 processors
491 * r0 = previous task_struct, r1 = previous thread_info, r2 = next thread_info
492 * previous and next are guaranteed not to be the same.
493 */
494ENTRY(__switch_to)
495	add	ip, r1, #TI_CPU_SAVE
496	stm.w	(r4 - r15), [ip]+
497	stm.w	(r16 - r27, sp, lr), [ip]+
498
499#ifdef	CONFIG_UNICORE_FPU_F64
500	add	ip, r1, #TI_FPSTATE
501	sfm.w	(f0  - f7 ), [ip]+
502	sfm.w	(f8  - f15), [ip]+
503	sfm.w	(f16 - f23), [ip]+
504	sfm.w	(f24 - f31), [ip]+
505	cff	r4, s31
506	stw	r4, [ip]
507
508	add	ip, r2, #TI_FPSTATE
509	lfm.w	(f0  - f7 ), [ip]+
510	lfm.w	(f8  - f15), [ip]+
511	lfm.w	(f16 - f23), [ip]+
512	lfm.w	(f24 - f31), [ip]+
513	ldw	r4, [ip]
514	ctf	r4, s31
515#endif
516	add	ip, r2, #TI_CPU_SAVE
517	ldm.w	(r4 - r15), [ip]+
518	ldm	(r16 - r27, sp, pc), [ip]+	@ Load all regs saved previously
519ENDPROC(__switch_to)
520
521	.align	5
522/*
523 * This is the fast syscall return path.  We do as little as
524 * possible here, and this includes saving r0 back into the PRIV
525 * stack.
526 */
527ret_fast_syscall:
528	disable_irq r1				@ disable interrupts
529	ldw	r1, [tsk+], #TI_FLAGS
530	cand.a	r1, #_TIF_WORK_MASK
531	bne	fast_work_pending
532
533	@ fast_restore_user_regs
534	restore_user_regs fast = 1, offset = S_OFF
535
536/*
537 * Ok, we need to do extra processing, enter the slow path.
538 */
539fast_work_pending:
540	stw.w	r0, [sp+], #S_R0+S_OFF		@ returned r0
541work_pending:
542	cand.a	r1, #_TIF_NEED_RESCHED
543	bne	work_resched
544	mov	r0, sp				@ 'regs'
545	mov	r2, why				@ 'syscall'
546	cand.a	r1, #_TIF_SIGPENDING		@ delivering a signal?
547	cmovne	why, #0				@ prevent further restarts
548	b.l	do_notify_resume
549	b	ret_slow_syscall		@ Check work again
550
551work_resched:
552	b.l	schedule
553/*
554 * "slow" syscall return path.  "why" tells us if this was a real syscall.
555 */
556ENTRY(ret_to_user)
557ret_slow_syscall:
558	disable_irq r1				@ disable interrupts
559	get_thread_info tsk			@ epip4d, one path error?!
560	ldw	r1, [tsk+], #TI_FLAGS
561	cand.a	r1, #_TIF_WORK_MASK
562	bne	work_pending
563no_work_pending:
564	@ slow_restore_user_regs
565	restore_user_regs fast = 0, offset = 0
566ENDPROC(ret_to_user)
567
568/*
569 * This is how we return from a fork.
570 */
571ENTRY(ret_from_fork)
572	b.l	schedule_tail
573	b	ret_slow_syscall
574ENDPROC(ret_from_fork)
575
576ENTRY(ret_from_kernel_thread)
577	b.l	schedule_tail
578	mov	r0, r5
579	adr	lr, ret_slow_syscall
580	mov	pc, r4
581ENDPROC(ret_from_kernel_thread)
582
583/*=============================================================================
584 * SWI handler
585 *-----------------------------------------------------------------------------
586 */
587	.align	5
588ENTRY(vector_swi)
589	sub	sp, sp, #S_FRAME_SIZE
590	stm	(r0 - r15), [sp]+		@ Calling r0 - r15
591	add	r8, sp, #S_R16
592	stm	(r16 - r28), [r8]+		@ Calling r16 - r28
593	add	r8, sp, #S_PC
594	stur	(sp, lr), [r8-]			@ Calling sp, lr
595	mov	r8, bsr				@ called from non-REAL mode
596	stw	lr, [sp+], #S_PC		@ Save calling PC
597	stw	r8, [sp+], #S_PSR		@ Save ASR
598	stw	r0, [sp+], #S_OLD_R0		@ Save OLD_R0
599	zero_fp
600
601	/*
602	 * Get the system call number.
603	 */
604	sub	ip, lr, #4
605	ldw.u	scno, [ip]			@ get SWI instruction
606
607#ifdef CONFIG_ALIGNMENT_TRAP
608	ldw	ip, __cr_alignment
609	ldw	ip, [ip]
610	movc	p0.c1, ip, #0                   @ update control register
611#endif
612	enable_irq ip
613
614	get_thread_info tsk
615	ldw	tbl, =sys_call_table		@ load syscall table pointer
616
617	andn	scno, scno, #0xff000000		@ mask off SWI op-code
618	andn	scno, scno, #0x00ff0000		@ mask off SWI op-code
619
620	stm.w	(r4, r5), [sp-]			@ push fifth and sixth args
621	ldw	ip, [tsk+], #TI_FLAGS		@ check for syscall tracing
622	cand.a	ip, #_TIF_SYSCALL_TRACE		@ are we tracing syscalls?
623	bne	__sys_trace
624
625	csub.a	scno, #__NR_syscalls		@ check upper syscall limit
626	adr	lr, ret_fast_syscall		@ return address
627	bea	1f
628	ldw	pc, [tbl+], scno << #2		@ call sys_* routine
6291:
630	add	r1, sp, #S_OFF
6312:	mov	why, #0				@ no longer a real syscall
632	b	sys_ni_syscall			@ not private func
633
634	/*
635	 * This is the really slow path.  We're going to be doing
636	 * context switches, and waiting for our parent to respond.
637	 */
638__sys_trace:
639	mov	r2, scno
640	add	r1, sp, #S_OFF
641	mov	r0, #0				@ trace entry [IP = 0]
642	b.l	syscall_trace
643
644	adr	lr, __sys_trace_return		@ return address
645	mov	scno, r0			@ syscall number (possibly new)
646	add	r1, sp, #S_R0 + S_OFF		@ pointer to regs
647	csub.a	scno, #__NR_syscalls		@ check upper syscall limit
648	bea	2b
649	ldm	(r0 - r3), [r1]+		@ have to reload r0 - r3
650	ldw	pc, [tbl+], scno << #2		@ call sys_* routine
651
652__sys_trace_return:
653	stw.w	r0, [sp+], #S_R0 + S_OFF	@ save returned r0
654	mov	r2, scno
655	mov	r1, sp
656	mov	r0, #1				@ trace exit [IP = 1]
657	b.l	syscall_trace
658	b	ret_slow_syscall
659
660	.align	5
661#ifdef CONFIG_ALIGNMENT_TRAP
662	.type	__cr_alignment, #object
663__cr_alignment:
664	.word	cr_alignment
665#endif
666	.ltorg
667
668ENTRY(sys_rt_sigreturn)
669		add	r0, sp, #S_OFF
670		mov	why, #0		@ prevent syscall restart handling
671		b	__sys_rt_sigreturn
672ENDPROC(sys_rt_sigreturn)
673
674	__INIT
675
676/*
677 * Vector stubs.
678 *
679 * This code is copied to 0xffff0200 so we can use branches in the
680 * vectors, rather than ldr's.  Note that this code must not
681 * exceed 0x300 bytes.
682 *
683 * Common stub entry macro:
684 *   Enter in INTR mode, bsr = PRIV/USER ASR, lr = PRIV/USER PC
685 *
686 * SP points to a minimal amount of processor-private memory, the address
687 * of which is copied into r0 for the mode specific abort handler.
688 */
689	.macro	vector_stub, name, mode
690	.align	5
691
692vector_\name:
693	@
694	@ Save r0, lr_<exception> (parent PC) and bsr_<exception>
695	@ (parent ASR)
696	@
697	stw	r0, [sp]
698	stw	lr, [sp+], #4		@ save r0, lr
699	mov	lr, bsr
700	stw	lr, [sp+], #8		@ save bsr
701
702	@
703	@ Prepare for PRIV mode.  INTRs remain disabled.
704	@
705	mov	r0, asr
706	xor	r0, r0, #(\mode ^ PRIV_MODE)
707	mov.a	bsr, r0
708
709	@
710	@ the branch table must immediately follow this code
711	@
712	and	lr, lr, #0x03
713	add	lr, lr, #1
714	mov	r0, sp
715	ldw	lr, [pc+], lr << #2
716	mov.a	pc, lr			@ branch to handler in PRIV mode
717ENDPROC(vector_\name)
718	.align	2
719	@ handler addresses follow this label
720	.endm
721
722	.globl	__stubs_start
723__stubs_start:
724/*
725 * Interrupt dispatcher
726 */
727	vector_stub	intr, INTR_MODE
728
729	.long	__intr_user			@  0  (USER)
730	.long	__invalid			@  1
731	.long	__invalid			@  2
732	.long	__intr_priv			@  3  (PRIV)
733
734/*
735 * Data abort dispatcher
736 * Enter in ABT mode, bsr = USER ASR, lr = USER PC
737 */
738	vector_stub	dabt, ABRT_MODE
739
740	.long	__dabt_user			@  0  (USER)
741	.long	__invalid			@  1
742	.long	__invalid			@  2  (INTR)
743	.long	__dabt_priv			@  3  (PRIV)
744
745/*
746 * Prefetch abort dispatcher
747 * Enter in ABT mode, bsr = USER ASR, lr = USER PC
748 */
749	vector_stub	pabt, ABRT_MODE
750
751	.long	__pabt_user			@  0 (USER)
752	.long	__invalid			@  1
753	.long	__invalid			@  2 (INTR)
754	.long	__pabt_priv			@  3 (PRIV)
755
756/*
757 * Undef instr entry dispatcher
758 * Enter in EXTN mode, bsr = PRIV/USER ASR, lr = PRIV/USER PC
759 */
760	vector_stub	extn, EXTN_MODE
761
762	.long	__extn_user			@  0 (USER)
763	.long	__invalid			@  1
764	.long	__invalid			@  2 (INTR)
765	.long	__extn_priv			@  3 (PRIV)
766
767/*
768 * We group all the following data together to optimise
769 * for CPUs with separate I & D caches.
770 */
771	.align	5
772
773.LCvswi:
774	.word	vector_swi
775
776	.globl	__stubs_end
777__stubs_end:
778
779	.equ	stubs_offset, __vectors_start + 0x200 - __stubs_start
780
781	.globl	__vectors_start
782__vectors_start:
783	jepriv	SYS_ERROR0
784	b	vector_extn + stubs_offset
785	ldw	pc, .LCvswi + stubs_offset
786	b	vector_pabt + stubs_offset
787	b	vector_dabt + stubs_offset
788	jepriv	SYS_ERROR0
789	b	vector_intr + stubs_offset
790	jepriv	SYS_ERROR0
791
792	.globl	__vectors_end
793__vectors_end:
794
795	.data
796
797	.globl	cr_alignment
798	.globl	cr_no_alignment
799cr_alignment:
800	.space	4
801cr_no_alignment:
802	.space	4
803