1/*
2 * Copyright (C) 2007-2009 Michal Simek <monstr@monstr.eu>
3 * Copyright (C) 2007-2009 PetaLogix
4 * Copyright (C) 2006 Atmark Techno, Inc.
5 *
6 * This file is subject to the terms and conditions of the GNU General Public
7 * License. See the file "COPYING" in the main directory of this archive
8 * for more details.
9 */
10
11#include <linux/linkage.h>
12#include <asm/thread_info.h>
13#include <linux/errno.h>
14#include <asm/entry.h>
15#include <asm/asm-offsets.h>
16#include <asm/registers.h>
17#include <asm/unistd.h>
18#include <asm/percpu.h>
19#include <asm/signal.h>
20
21#if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR
22	.macro	disable_irq
23	msrclr r0, MSR_IE
24	.endm
25
26	.macro	enable_irq
27	msrset r0, MSR_IE
28	.endm
29
30	.macro	clear_bip
31	msrclr r0, MSR_BIP
32	.endm
33#else
34	.macro	disable_irq
35	mfs r11, rmsr
36	andi r11, r11, ~MSR_IE
37	mts rmsr, r11
38	.endm
39
40	.macro	enable_irq
41	mfs r11, rmsr
42	ori r11, r11, MSR_IE
43	mts rmsr, r11
44	.endm
45
46	.macro	clear_bip
47	mfs r11, rmsr
48	andi r11, r11, ~MSR_BIP
49	mts rmsr, r11
50	.endm
51#endif
52
53ENTRY(_interrupt)
54	swi	r1, r0, PER_CPU(ENTRY_SP)	/* save the current sp */
55	swi	r11, r0, PER_CPU(R11_SAVE)	/* temporarily save r11 */
56	lwi	r11, r0, PER_CPU(KM)		/* load mode indicator */
57	beqid	r11, 1f
58	nop
59	brid	2f				/* jump over */
60	addik	r1, r1, (-PT_SIZE)	/* room for pt_regs (delay slot) */
611:						/* switch to kernel stack */
62	lwi	r1, r0, PER_CPU(CURRENT_SAVE)	/* get the saved current */
63	lwi	r1, r1, TS_THREAD_INFO		/* get the thread info */
64	/* calculate kernel stack pointer */
65	addik	r1, r1, THREAD_SIZE - PT_SIZE
662:
67	swi	r11, r1, PT_MODE		/* store the mode */
68	lwi	r11, r0, PER_CPU(R11_SAVE)	/* reload r11 */
69	swi	r2, r1, PT_R2
70	swi	r3, r1, PT_R3
71	swi	r4, r1, PT_R4
72	swi	r5, r1, PT_R5
73	swi	r6, r1, PT_R6
74	swi	r7, r1, PT_R7
75	swi	r8, r1, PT_R8
76	swi	r9, r1, PT_R9
77	swi	r10, r1, PT_R10
78	swi	r11, r1, PT_R11
79	swi	r12, r1, PT_R12
80	swi	r13, r1, PT_R13
81	swi	r14, r1, PT_R14
82	swi	r14, r1, PT_PC
83	swi	r15, r1, PT_R15
84	swi	r16, r1, PT_R16
85	swi	r17, r1, PT_R17
86	swi	r18, r1, PT_R18
87	swi	r19, r1, PT_R19
88	swi	r20, r1, PT_R20
89	swi	r21, r1, PT_R21
90	swi	r22, r1, PT_R22
91	swi	r23, r1, PT_R23
92	swi	r24, r1, PT_R24
93	swi	r25, r1, PT_R25
94	swi	r26, r1, PT_R26
95	swi	r27, r1, PT_R27
96	swi	r28, r1, PT_R28
97	swi	r29, r1, PT_R29
98	swi	r30, r1, PT_R30
99	swi	r31, r1, PT_R31
100	/* special purpose registers */
101	mfs	r11, rmsr
102	swi	r11, r1, PT_MSR
103	mfs	r11, rear
104	swi	r11, r1, PT_EAR
105	mfs	r11, resr
106	swi	r11, r1, PT_ESR
107	mfs	r11, rfsr
108	swi	r11, r1, PT_FSR
109	/* reload original stack pointer and save it */
110	lwi	r11, r0, PER_CPU(ENTRY_SP)
111	swi	r11, r1, PT_R1
112	/* update mode indicator we are in kernel mode */
113	addik	r11, r0, 1
114	swi	r11, r0, PER_CPU(KM)
115	/* restore r31 */
116	lwi	r31, r0, PER_CPU(CURRENT_SAVE)
117	/* prepare the link register, the argument and jump */
118	addik	r15, r0, ret_from_intr - 8
119	addk	r6, r0, r15
120	braid	do_IRQ
121	add	r5, r0, r1
122
123ret_from_intr:
124	lwi	r11, r1, PT_MODE
125	bneid	r11, no_intr_resched
126
1273:
128	lwi	r6, r31, TS_THREAD_INFO	/* get thread info */
129	lwi	r19, r6, TI_FLAGS	/* get flags in thread info */
130				/* do an extra work if any bits are set */
131
132	andi	r11, r19, _TIF_NEED_RESCHED
133	beqi	r11, 1f
134	bralid	r15, schedule
135	nop
136	bri	3b
1371:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
138	beqid	r11, no_intr_resched
139	addk	r5, r1, r0
140	bralid	r15, do_notify_resume
141	addk	r6, r0, r0
142	bri	3b
143
144no_intr_resched:
145	/* Disable interrupts, we are now committed to the state restore */
146	disable_irq
147
148	/* save mode indicator */
149	lwi	r11, r1, PT_MODE
150	swi	r11, r0, PER_CPU(KM)
151
152	/* save r31 */
153	swi	r31, r0, PER_CPU(CURRENT_SAVE)
154restore_context:
155	/* special purpose registers */
156	lwi	r11, r1, PT_FSR
157	mts	rfsr, r11
158	lwi	r11, r1, PT_ESR
159	mts	resr, r11
160	lwi	r11, r1, PT_EAR
161	mts	rear, r11
162	lwi	r11, r1, PT_MSR
163	mts	rmsr, r11
164
165	lwi	r31, r1, PT_R31
166	lwi	r30, r1, PT_R30
167	lwi	r29, r1, PT_R29
168	lwi	r28, r1, PT_R28
169	lwi	r27, r1, PT_R27
170	lwi	r26, r1, PT_R26
171	lwi	r25, r1, PT_R25
172	lwi	r24, r1, PT_R24
173	lwi	r23, r1, PT_R23
174	lwi	r22, r1, PT_R22
175	lwi	r21, r1, PT_R21
176	lwi	r20, r1, PT_R20
177	lwi	r19, r1, PT_R19
178	lwi	r18, r1, PT_R18
179	lwi	r17, r1, PT_R17
180	lwi	r16, r1, PT_R16
181	lwi	r15, r1, PT_R15
182	lwi	r14, r1, PT_PC
183	lwi	r13, r1, PT_R13
184	lwi	r12, r1, PT_R12
185	lwi	r11, r1, PT_R11
186	lwi	r10, r1, PT_R10
187	lwi	r9, r1, PT_R9
188	lwi	r8, r1, PT_R8
189	lwi	r7, r1, PT_R7
190	lwi	r6, r1, PT_R6
191	lwi	r5, r1, PT_R5
192	lwi	r4, r1, PT_R4
193	lwi	r3, r1, PT_R3
194	lwi	r2, r1, PT_R2
195	lwi	r1, r1, PT_R1
196	rtid	r14, 0
197	nop
198
199ENTRY(_reset)
200	brai	0;
201
202ENTRY(_user_exception)
203	swi	r1, r0, PER_CPU(ENTRY_SP)	/* save the current sp */
204	swi	r11, r0, PER_CPU(R11_SAVE)	/* temporarily save r11 */
205	lwi	r11, r0, PER_CPU(KM)		/* load mode indicator */
206	beqid	r11, 1f				/* Already in kernel mode? */
207	nop
208	brid	2f				/* jump over */
209	addik	r1, r1, (-PT_SIZE)	/* Room for pt_regs (delay slot) */
2101:						/* Switch to kernel stack */
211	lwi	r1, r0, PER_CPU(CURRENT_SAVE)	/* get the saved current */
212	lwi	r1, r1, TS_THREAD_INFO		/* get the thread info */
213	/* calculate kernel stack pointer */
214	addik	r1, r1, THREAD_SIZE - PT_SIZE
2152:
216	swi	r11, r1, PT_MODE		/* store the mode */
217	lwi	r11, r0, PER_CPU(R11_SAVE)	/* reload r11 */
218	/* save them on stack */
219	swi	r2, r1, PT_R2
220	swi	r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */
221	swi	r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */
222	swi	r5, r1, PT_R5
223	swi	r6, r1, PT_R6
224	swi	r7, r1, PT_R7
225	swi	r8, r1, PT_R8
226	swi	r9, r1, PT_R9
227	swi	r10, r1, PT_R10
228	swi	r11, r1, PT_R11
229	/* r12: _always_ in clobber list; see unistd.h */
230	swi	r12, r1, PT_R12
231	swi	r13, r1, PT_R13
232	/* r14: _always_ in clobber list; see unistd.h */
233	swi	r14, r1, PT_R14
234	/* but we want to return to the next inst. */
235	addik	r14, r14, 0x4
236	swi	r14, r1, PT_PC		/* increment by 4 and store in pc */
237	swi	r15, r1, PT_R15
238	swi	r16, r1, PT_R16
239	swi	r17, r1, PT_R17
240	swi	r18, r1, PT_R18
241	swi	r19, r1, PT_R19
242	swi	r20, r1, PT_R20
243	swi	r21, r1, PT_R21
244	swi	r22, r1, PT_R22
245	swi	r23, r1, PT_R23
246	swi	r24, r1, PT_R24
247	swi	r25, r1, PT_R25
248	swi	r26, r1, PT_R26
249	swi	r27, r1, PT_R27
250	swi	r28, r1, PT_R28
251	swi	r29, r1, PT_R29
252	swi	r30, r1, PT_R30
253	swi	r31, r1, PT_R31
254
255	disable_irq
256	nop		/* make sure IE bit is in effect */
257	clear_bip	/* once IE is in effect it is safe to clear BIP */
258	nop
259
260	/* special purpose registers */
261	mfs	r11, rmsr
262	swi	r11, r1, PT_MSR
263	mfs	r11, rear
264	swi	r11, r1, PT_EAR
265	mfs	r11, resr
266	swi	r11, r1, PT_ESR
267	mfs	r11, rfsr
268	swi	r11, r1, PT_FSR
269	/* reload original stack pointer and save it */
270	lwi	r11, r0, PER_CPU(ENTRY_SP)
271	swi	r11, r1, PT_R1
272	/* update mode indicator we are in kernel mode */
273	addik	r11, r0, 1
274	swi	r11, r0, PER_CPU(KM)
275	/* restore r31 */
276	lwi	r31, r0, PER_CPU(CURRENT_SAVE)
277	/* re-enable interrupts now we are in kernel mode */
278	enable_irq
279
280	/* See if the system call number is valid. */
281	addi	r11, r12, -__NR_syscalls
282	bgei	r11, 1f			/* return to user if not valid */
283	/* Figure out which function to use for this system call. */
284	/* Note Microblaze barrel shift is optional, so don't rely on it */
285	add	r12, r12, r12			/* convert num -> ptr */
286	addik	r30, r0, 1			/* restarts allowed */
287	add	r12, r12, r12
288	lwi	r12, r12, sys_call_table	/* Get function pointer */
289	addik	r15, r0, ret_to_user-8		/* set return address */
290	bra	r12				/* Make the system call. */
291	bri	0				/* won't reach here */
2921:
293	brid	ret_to_user			/* jump to syscall epilogue */
294	addi	r3, r0, -ENOSYS			/* set errno in delay slot */
295
296/*
297 * Debug traps are like a system call, but entered via brki r14, 0x60
298 * All we need to do is send the SIGTRAP signal to current, ptrace and
299 * do_notify_resume will handle the rest
300 */
301ENTRY(_debug_exception)
302	swi	r1, r0, PER_CPU(ENTRY_SP)	/* save the current sp */
303	lwi	r1, r0, PER_CPU(CURRENT_SAVE)	/* get the saved current */
304	lwi	r1, r1, TS_THREAD_INFO		/* get the thread info */
305	addik	r1, r1, THREAD_SIZE - PT_SIZE	/* get the kernel stack */
306	swi	r11, r0, PER_CPU(R11_SAVE)	/* temporarily save r11 */
307	lwi	r11, r0, PER_CPU(KM)		/* load mode indicator */
308//save_context:
309	swi	r11, r1, PT_MODE	/* store the mode */
310	lwi	r11, r0, PER_CPU(R11_SAVE)	/* reload r11 */
311	/* save them on stack */
312	swi	r2, r1, PT_R2
313	swi	r3, r1, PT_R3 /* r3: _always_ in clobber list; see unistd.h */
314	swi	r4, r1, PT_R4 /* r4: _always_ in clobber list; see unistd.h */
315	swi	r5, r1, PT_R5
316	swi	r6, r1, PT_R6
317	swi	r7, r1, PT_R7
318	swi	r8, r1, PT_R8
319	swi	r9, r1, PT_R9
320	swi	r10, r1, PT_R10
321	swi	r11, r1, PT_R11
322	/* r12: _always_ in clobber list; see unistd.h */
323	swi	r12, r1, PT_R12
324	swi	r13, r1, PT_R13
325	/* r14: _always_ in clobber list; see unistd.h */
326	swi	r14, r1, PT_R14
327	swi	r14, r1, PT_PC /* Will return to interrupted instruction */
328	swi	r15, r1, PT_R15
329	swi	r16, r1, PT_R16
330	swi	r17, r1, PT_R17
331	swi	r18, r1, PT_R18
332	swi	r19, r1, PT_R19
333	swi	r20, r1, PT_R20
334	swi	r21, r1, PT_R21
335	swi	r22, r1, PT_R22
336	swi	r23, r1, PT_R23
337	swi	r24, r1, PT_R24
338	swi	r25, r1, PT_R25
339	swi	r26, r1, PT_R26
340	swi	r27, r1, PT_R27
341	swi	r28, r1, PT_R28
342	swi	r29, r1, PT_R29
343	swi	r30, r1, PT_R30
344	swi	r31, r1, PT_R31
345
346	disable_irq
347	nop		/* make sure IE bit is in effect */
348	clear_bip	/* once IE is in effect it is safe to clear BIP */
349	nop
350
351	/* special purpose registers */
352	mfs	r11, rmsr
353	swi	r11, r1, PT_MSR
354	mfs	r11, rear
355	swi	r11, r1, PT_EAR
356	mfs	r11, resr
357	swi	r11, r1, PT_ESR
358	mfs	r11, rfsr
359	swi	r11, r1, PT_FSR
360	/* reload original stack pointer and save it */
361	lwi	r11, r0, PER_CPU(ENTRY_SP)
362	swi	r11, r1, PT_R1
363	/* update mode indicator we are in kernel mode */
364	addik	r11, r0, 1
365	swi	r11, r0, PER_CPU(KM)
366	/* restore r31 */
367	lwi	r31, r0, PER_CPU(CURRENT_SAVE)
368	/* re-enable interrupts now we are in kernel mode */
369	enable_irq
370
371	addi	r5, r0, SIGTRAP			/* sending the trap signal */
372	add	r6, r0, r31			/* to current */
373	bralid	r15, send_sig
374	add	r7, r0, r0			/* 3rd param zero */
375
376	addik	r30, r0, 1			/* restarts allowed ??? */
377	/* Restore r3/r4 to work around how ret_to_user works */
378	lwi	r3, r1, PT_R3
379	lwi	r4, r1, PT_R4
380	bri	ret_to_user
381
382ENTRY(_break)
383	bri	0
384
385/* struct task_struct *_switch_to(struct thread_info *prev,
386					struct thread_info *next); */
387ENTRY(_switch_to)
388	/* prepare return value */
389	addk	r3, r0, r31
390
391	/* save registers in cpu_context */
392	/* use r11 and r12, volatile registers, as temp register */
393	addik	r11, r5, TI_CPU_CONTEXT
394	swi	r1, r11, CC_R1
395	swi	r2, r11, CC_R2
396	/* skip volatile registers.
397	 * they are saved on stack when we jumped to _switch_to() */
398	/* dedicated registers */
399	swi	r13, r11, CC_R13
400	swi	r14, r11, CC_R14
401	swi	r15, r11, CC_R15
402	swi	r16, r11, CC_R16
403	swi	r17, r11, CC_R17
404	swi	r18, r11, CC_R18
405	/* save non-volatile registers */
406	swi	r19, r11, CC_R19
407	swi	r20, r11, CC_R20
408	swi	r21, r11, CC_R21
409	swi	r22, r11, CC_R22
410	swi	r23, r11, CC_R23
411	swi	r24, r11, CC_R24
412	swi	r25, r11, CC_R25
413	swi	r26, r11, CC_R26
414	swi	r27, r11, CC_R27
415	swi	r28, r11, CC_R28
416	swi	r29, r11, CC_R29
417	swi	r30, r11, CC_R30
418	/* special purpose registers */
419	mfs	r12, rmsr
420	swi	r12, r11, CC_MSR
421	mfs	r12, rear
422	swi	r12, r11, CC_EAR
423	mfs	r12, resr
424	swi	r12, r11, CC_ESR
425	mfs	r12, rfsr
426	swi	r12, r11, CC_FSR
427
428	/* update r31, the current */
429	lwi	r31, r6, TI_TASK
430	swi	r31, r0, PER_CPU(CURRENT_SAVE)
431
432	/* get new process' cpu context and restore */
433	addik	r11, r6, TI_CPU_CONTEXT
434
435	/* special purpose registers */
436	lwi	r12, r11, CC_FSR
437	mts	rfsr, r12
438	lwi	r12, r11, CC_ESR
439	mts	resr, r12
440	lwi	r12, r11, CC_EAR
441	mts	rear, r12
442	lwi	r12, r11, CC_MSR
443	mts	rmsr, r12
444	/* non-volatile registers */
445	lwi	r30, r11, CC_R30
446	lwi	r29, r11, CC_R29
447	lwi	r28, r11, CC_R28
448	lwi	r27, r11, CC_R27
449	lwi	r26, r11, CC_R26
450	lwi	r25, r11, CC_R25
451	lwi	r24, r11, CC_R24
452	lwi	r23, r11, CC_R23
453	lwi	r22, r11, CC_R22
454	lwi	r21, r11, CC_R21
455	lwi	r20, r11, CC_R20
456	lwi	r19, r11, CC_R19
457	/* dedicated registers */
458	lwi	r18, r11, CC_R18
459	lwi	r17, r11, CC_R17
460	lwi	r16, r11, CC_R16
461	lwi	r15, r11, CC_R15
462	lwi	r14, r11, CC_R14
463	lwi	r13, r11, CC_R13
464	/* skip volatile registers */
465	lwi	r2, r11, CC_R2
466	lwi	r1, r11, CC_R1
467
468	rtsd	r15, 8
469	nop
470
471ENTRY(ret_from_fork)
472	addk	r5, r0, r3
473	brlid	r15, schedule_tail
474	nop
475	swi	r31, r1, PT_R31		/* save r31 in user context. */
476			/* will soon be restored to r31 in ret_to_user */
477	addk	r3, r0, r0
478	brid	ret_to_user
479	nop
480
481ENTRY(ret_from_kernel_thread)
482	brlid	r15, schedule_tail
483	addk	r5, r0, r3
484	brald	r15, r20
485	addk	r5, r0, r19
486	brid	ret_to_user
487	addk	r3, r0, r0
488
489work_pending:
490	lwi	r11, r1, PT_MODE
491	bneid	r11, 2f
4923:
493	enable_irq
494	andi	r11, r19, _TIF_NEED_RESCHED
495	beqi	r11, 1f
496	bralid	r15, schedule
497	nop
498	bri	4f
4991:	andi	r11, r19, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
500	beqi	r11, no_work_pending
501	addk	r5, r30, r0
502	bralid	r15, do_notify_resume
503	addik	r6, r0, 1
504	addk	r30, r0, r0	/* no restarts from now on */
5054:
506	disable_irq
507	lwi	r6, r31, TS_THREAD_INFO /* get thread info */
508	lwi	r19, r6, TI_FLAGS /* get flags in thread info */
509	bri	3b
510
511ENTRY(ret_to_user)
512	disable_irq
513
514	swi	r4, r1, PT_R4		/* return val */
515	swi	r3, r1, PT_R3		/* return val */
516
517	lwi	r6, r31, TS_THREAD_INFO /* get thread info */
518	lwi	r19, r6, TI_FLAGS /* get flags in thread info */
519	bnei	r19, work_pending /* do an extra work if any bits are set */
520no_work_pending:
521	disable_irq
522
5232:
524	/* save r31 */
525	swi	r31, r0, PER_CPU(CURRENT_SAVE)
526	/* save mode indicator */
527	lwi	r18, r1, PT_MODE
528	swi	r18, r0, PER_CPU(KM)
529//restore_context:
530	/* special purpose registers */
531	lwi	r18, r1, PT_FSR
532	mts	rfsr, r18
533	lwi	r18, r1, PT_ESR
534	mts	resr, r18
535	lwi	r18, r1, PT_EAR
536	mts	rear, r18
537	lwi	r18, r1, PT_MSR
538	mts	rmsr, r18
539
540	lwi	r31, r1, PT_R31
541	lwi	r30, r1, PT_R30
542	lwi	r29, r1, PT_R29
543	lwi	r28, r1, PT_R28
544	lwi	r27, r1, PT_R27
545	lwi	r26, r1, PT_R26
546	lwi	r25, r1, PT_R25
547	lwi	r24, r1, PT_R24
548	lwi	r23, r1, PT_R23
549	lwi	r22, r1, PT_R22
550	lwi	r21, r1, PT_R21
551	lwi	r20, r1, PT_R20
552	lwi	r19, r1, PT_R19
553	lwi	r18, r1, PT_R18
554	lwi	r17, r1, PT_R17
555	lwi	r16, r1, PT_R16
556	lwi	r15, r1, PT_R15
557	lwi	r14, r1, PT_PC
558	lwi	r13, r1, PT_R13
559	lwi	r12, r1, PT_R12
560	lwi	r11, r1, PT_R11
561	lwi	r10, r1, PT_R10
562	lwi	r9, r1, PT_R9
563	lwi	r8, r1, PT_R8
564	lwi	r7, r1, PT_R7
565	lwi	r6, r1, PT_R6
566	lwi	r5, r1, PT_R5
567	lwi	r4, r1, PT_R4		/* return val */
568	lwi	r3, r1, PT_R3		/* return val */
569	lwi	r2, r1, PT_R2
570	lwi	r1, r1, PT_R1
571
572	rtid	r14, 0
573	nop
574
575sys_rt_sigreturn_wrapper:
576	addk	r30, r0, r0		/* no restarts for this one */
577	brid	sys_rt_sigreturn
578	addk	r5, r1, r0
579
580	/* Interrupt vector table */
581	.section	.init.ivt, "ax"
582	.org 0x0
583	brai	_reset
584	brai	_user_exception
585	brai	_interrupt
586	brai	_break
587	brai	_hw_exception_handler
588	.org 0x60
589	brai	_debug_exception
590
591.section .rodata,"a"
592#include "syscall_table.S"
593
594syscall_table_size=(.-sys_call_table)
595
596type_SYSCALL:
597	.ascii "SYSCALL\0"
598type_IRQ:
599	.ascii "IRQ\0"
600type_IRQ_PREEMPT:
601	.ascii "IRQ (PREEMPTED)\0"
602type_SYSCALL_PREEMPT:
603	.ascii " SYSCALL (PREEMPTED)\0"
604
605	/*
606	 * Trap decoding for stack unwinder
607	 * Tuples are (start addr, end addr, string)
608	 * If return address lies on [start addr, end addr],
609	 * unwinder displays 'string'
610	 */
611
612	.align 4
613.global microblaze_trap_handlers
614microblaze_trap_handlers:
615	/* Exact matches come first */
616	.word ret_to_user  ; .word ret_to_user    ; .word type_SYSCALL
617	.word ret_from_intr; .word ret_from_intr  ; .word type_IRQ
618	/* Fuzzy matches go here */
619	.word ret_from_intr; .word no_intr_resched; .word type_IRQ_PREEMPT
620	.word work_pending ; .word no_work_pending; .word type_SYSCALL_PREEMPT
621	/* End of table */
622	.word 0             ; .word 0               ; .word 0
623