1/*
2 * arch/score/kernel/entry.S
3 *
4 * Score Processor version.
5 *
6 * Copyright (C) 2009 Sunplus Core Technology Co., Ltd.
7 *  Chen Liqin <liqin.chen@sunplusct.com>
8 *  Lennox Wu <lennox.wu@sunplusct.com>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, see the file COPYING, or write
22 * to the Free Software Foundation, Inc.,
23 * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24 */
25
26#include <linux/err.h>
27#include <linux/init.h>
28#include <linux/linkage.h>
29
30#include <asm/asmmacro.h>
31#include <asm/thread_info.h>
32#include <asm/unistd.h>
33
34/*
35 * disable interrupts.
36 */
37.macro	disable_irq
38	mfcr	r8, cr0
39	srli	r8, r8, 1
40	slli	r8, r8, 1
41	mtcr	r8, cr0
42	nop
43	nop
44	nop
45	nop
46	nop
47.endm
48
49/*
50 * enable interrupts.
51 */
52.macro	enable_irq
53	mfcr	r8, cr0
54	ori	r8, 1
55	mtcr	r8, cr0
56	nop
57	nop
58	nop
59	nop
60	nop
61.endm
62
63__INIT
64ENTRY(debug_exception_vector)
65	nop!
66	nop!
67	nop!
68	nop!
69	nop!
70	nop!
71	nop!
72	nop!
73
74ENTRY(general_exception_vector)			# should move to addr 0x200
75	j	general_exception
76	nop!
77	nop!
78	nop!
79	nop!
80	nop!
81	nop!
82
83ENTRY(interrupt_exception_vector)		# should move to addr 0x210
84	j	interrupt_exception
85	nop!
86	nop!
87	nop!
88	nop!
89	nop!
90	nop!
91
92	.section ".text", "ax"
93	.align	2;
94general_exception:
95	mfcr	r31, cr2
96	nop
97	la	r30, exception_handlers
98	andi	r31, 0x1f			# get ecr.exc_code
99	slli	r31, r31, 2
100	add	r30, r30, r31
101	lw	r30, [r30]
102	br	r30
103
104interrupt_exception:
105	SAVE_ALL
106	mfcr	r4, cr2
107	nop
108	lw	r16, [r28, TI_REGS]
109	sw	r0, [r28, TI_REGS]
110	la	r3, ret_from_irq
111	srli	r4, r4, 18			# get ecr.ip[7:2], interrupt No.
112	mv	r5, r0
113	j	do_IRQ
114
115ENTRY(handle_nmi)				# NMI #1
116	SAVE_ALL
117	mv	r4, r0
118	la	r8, nmi_exception_handler
119	brl	r8
120	j	restore_all
121
122ENTRY(handle_adelinsn)				# AdEL-instruction #2
123	SAVE_ALL
124	mfcr	r8, cr6
125	nop
126	nop
127	sw	r8, [r0, PT_EMA]
128	mv	r4, r0
129	la	r8, do_adelinsn
130	brl	r8
131	mv	r4, r0
132	j	ret_from_exception
133	nop
134
135ENTRY(handle_ibe)				# BusEL-instruction #5
136	SAVE_ALL
137	mv	r4, r0
138	la	r8, do_be
139	brl	r8
140	mv	r4, r0
141	j	ret_from_exception
142	nop
143
144ENTRY(handle_pel)				# P-EL #6
145	SAVE_ALL
146	mv	r4, r0
147	la	r8, do_pel
148	brl	r8
149	mv	r4, r0
150	j	ret_from_exception
151	nop
152
153ENTRY(handle_ccu)				# CCU #8
154	SAVE_ALL
155	mv	r4, r0
156	la	r8, do_ccu
157	brl	r8
158	mv	r4, r0
159	j	ret_from_exception
160	nop
161
162ENTRY(handle_ri)				# RI #9
163	SAVE_ALL
164	mv	r4, r0
165	la	r8, do_ri
166	brl	r8
167	mv	r4, r0
168	j	ret_from_exception
169	nop
170
171ENTRY(handle_tr)				# Trap #10
172	SAVE_ALL
173	mv	r4, r0
174	la	r8, do_tr
175	brl	r8
176	mv	r4, r0
177	j	ret_from_exception
178	nop
179
180ENTRY(handle_adedata)				# AdES-instruction #12
181	SAVE_ALL
182	mfcr	r8, cr6
183	nop
184	nop
185	sw	r8, [r0, PT_EMA]
186	mv	r4, r0
187	la	r8, do_adedata
188	brl	r8
189	mv	r4, r0
190	j	ret_from_exception
191	nop
192
193ENTRY(handle_cee)				# CeE #16
194	SAVE_ALL
195	mv	r4, r0
196	la	r8, do_cee
197	brl	r8
198	mv	r4, r0
199	j	ret_from_exception
200	nop
201
202ENTRY(handle_cpe)				# CpE #17
203	SAVE_ALL
204	mv	r4, r0
205	la	r8, do_cpe
206	brl	r8
207	mv	r4, r0
208	j	ret_from_exception
209	nop
210
211ENTRY(handle_dbe)				# BusEL-data #18
212	SAVE_ALL
213	mv	r4, r0
214	la	r8, do_be
215	brl	r8
216	mv	r4, r0
217	j	ret_from_exception
218	nop
219
220ENTRY(handle_reserved)				# others
221	SAVE_ALL
222	mv	r4, r0
223	la	r8, do_reserved
224	brl	r8
225	mv	r4, r0
226	j	ret_from_exception
227	nop
228
229#ifndef CONFIG_PREEMPT
230#define resume_kernel	restore_all
231#else
232#define __ret_from_irq	ret_from_exception
233#endif
234
235	.align	2
236#ifndef CONFIG_PREEMPT
237ENTRY(ret_from_exception)
238	disable_irq			# preempt stop
239	nop
240	j	__ret_from_irq
241	nop
242#endif
243
244ENTRY(ret_from_irq)
245	sw	r16, [r28, TI_REGS]
246
247ENTRY(__ret_from_irq)
248	lw	r8, [r0, PT_PSR]	# returning to kernel mode?
249	andri.c	r8, r8, KU_USER
250	beq	resume_kernel
251
252resume_userspace:
253	disable_irq
254	lw	r6, [r28, TI_FLAGS]	# current->work
255	li	r8, _TIF_WORK_MASK
256	and.c	r8, r8, r6		# ignoring syscall_trace
257	bne	work_pending
258	nop
259	j	restore_all
260	nop
261
262#ifdef CONFIG_PREEMPT
263resume_kernel:
264	disable_irq
265	lw	r8, [r28, TI_PRE_COUNT]
266	cmpz.c	r8
267	bne	restore_all
268need_resched:
269	lw	r8, [r28, TI_FLAGS]
270	andri.c	r9, r8, _TIF_NEED_RESCHED
271	beq	restore_all
272	lw	r8, [r28, PT_PSR]		# Interrupts off?
273	andri.c	r8, r8, 1
274	beq	restore_all
275	bl	preempt_schedule_irq
276	nop
277	j	need_resched
278	nop
279#endif
280
281ENTRY(ret_from_kernel_thread)
282	bl	schedule_tail			# r4=struct task_struct *prev
283	nop
284	mv	r4, r13
285	brl	r12
286	j	syscall_exit
287
288ENTRY(ret_from_fork)
289	bl	schedule_tail			# r4=struct task_struct *prev
290
291ENTRY(syscall_exit)
292	nop
293	disable_irq
294	lw	r6, [r28, TI_FLAGS]		# current->work
295	li	r8, _TIF_WORK_MASK
296	and.c	r8, r6, r8
297	bne	syscall_exit_work
298
299ENTRY(restore_all)					# restore full frame
300	RESTORE_ALL_AND_RET
301
302work_pending:
303	andri.c	r8, r6, _TIF_NEED_RESCHED # r6 is preloaded with TI_FLAGS
304	beq	work_notifysig
305work_resched:
306	bl	schedule
307	nop
308	disable_irq
309	lw	r6, [r28, TI_FLAGS]
310	li	r8, _TIF_WORK_MASK
311	and.c	r8, r6, r8	# is there any work to be done
312				# other than syscall tracing?
313	beq	restore_all
314	andri.c	r8, r6, _TIF_NEED_RESCHED
315	bne	work_resched
316
317work_notifysig:
318	mv	r4, r0
319	li	r5, 0
320	bl	do_notify_resume	# r6 already loaded
321	nop
322	j	resume_userspace
323	nop
324
325ENTRY(syscall_exit_work)
326	li	r8, _TIF_SYSCALL_TRACE
327	and.c	r8, r8, r6		# r6 is preloaded with TI_FLAGS
328	beq	work_pending		# trace bit set?
329	nop
330	enable_irq
331	mv	r4, r0
332	li	r5, 1
333	bl	do_syscall_trace
334	nop
335	b	resume_userspace
336	nop
337
338.macro	save_context	reg
339	sw	r12, [\reg, THREAD_REG12];
340	sw	r13, [\reg, THREAD_REG13];
341	sw	r14, [\reg, THREAD_REG14];
342	sw	r15, [\reg, THREAD_REG15];
343	sw	r16, [\reg, THREAD_REG16];
344	sw	r17, [\reg, THREAD_REG17];
345	sw	r18, [\reg, THREAD_REG18];
346	sw	r19, [\reg, THREAD_REG19];
347	sw	r20, [\reg, THREAD_REG20];
348	sw	r21, [\reg, THREAD_REG21];
349	sw	r29, [\reg, THREAD_REG29];
350	sw	r2, [\reg, THREAD_REG2];
351	sw	r0, [\reg, THREAD_REG0]
352.endm
353
354.macro	restore_context	reg
355	lw	r12, [\reg, THREAD_REG12];
356	lw	r13, [\reg, THREAD_REG13];
357	lw	r14, [\reg, THREAD_REG14];
358	lw	r15, [\reg, THREAD_REG15];
359	lw	r16, [\reg, THREAD_REG16];
360	lw	r17, [\reg, THREAD_REG17];
361	lw	r18, [\reg, THREAD_REG18];
362	lw	r19, [\reg, THREAD_REG19];
363	lw	r20, [\reg, THREAD_REG20];
364	lw	r21, [\reg, THREAD_REG21];
365	lw	r29, [\reg, THREAD_REG29];
366	lw	r0, [\reg, THREAD_REG0];
367	lw	r2, [\reg, THREAD_REG2];
368	lw	r3, [\reg, THREAD_REG3]
369.endm
370
371/*
372 * task_struct *resume(task_struct *prev, task_struct *next,
373 *			struct thread_info *next_ti)
374 */
375ENTRY(resume)
376	mfcr	r9, cr0
377	nop
378	nop
379	sw	r9, [r4, THREAD_PSR]
380	save_context	r4
381	sw	r3, [r4, THREAD_REG3]
382
383	mv	r28, r6
384	restore_context	r5
385	mv	r8, r6
386	addi	r8, KERNEL_STACK_SIZE
387	subi	r8, 32
388	la 	r9, kernelsp;
389	sw 	r8, [r9];
390
391	mfcr	r9, cr0
392	ldis	r7, 0x00ff
393	nop
394	and	r9, r9, r7
395	lw	r6, [r5, THREAD_PSR]
396	not	r7, r7
397	and	r6, r6, r7
398	or	r6, r6, r9
399	mtcr	r6, cr0
400	nop; nop; nop; nop; nop
401	br	r3
402
403ENTRY(handle_sys)
404	SAVE_ALL
405	sw	r8, [r0, 16]		# argument 5 from user r8
406	sw	r9, [r0, 20]		# argument 6 from user r9
407	enable_irq
408
409	sw	r4, [r0, PT_ORIG_R4]	#for restart syscall
410	sw	r7, [r0, PT_ORIG_R7]	#for restart syscall
411	sw	r27, [r0, PT_IS_SYSCALL] # it from syscall
412
413	lw	r9, [r0, PT_EPC]	# skip syscall on return
414	addi	r9, 4
415	sw	r9, [r0, PT_EPC]
416
417	cmpi.c	r27, __NR_syscalls 	# check syscall number
418	bcs	illegal_syscall
419
420	slli	r8, r27, 2		# get syscall routine
421	la	r11, sys_call_table
422	add	r11, r11, r8
423	lw	r10, [r11]		# get syscall entry
424
425	cmpz.c	r10
426	beq	illegal_syscall
427
428	lw	r8, [r28, TI_FLAGS]
429	li	r9, _TIF_SYSCALL_TRACE
430	and.c	r8, r8, r9
431	bne	syscall_trace_entry
432
433	brl	r10			# Do The Real system call
434
435	cmpi.c	r4, 0
436	blt	1f
437	ldi	r8, 0
438	sw	r8, [r0, PT_R7]
439	b 2f
4401:
441	cmpi.c	r4, -MAX_ERRNO - 1
442	ble	2f
443	ldi	r8, 0x1;
444	sw	r8, [r0, PT_R7]
445	neg	r4, r4
4462:
447	sw	r4, [r0, PT_R4]		# save result
448
449syscall_return:
450	disable_irq
451	lw	r6, [r28, TI_FLAGS]	# current->work
452	li	r8, _TIF_WORK_MASK
453	and.c	r8, r6, r8
454	bne	syscall_return_work
455	j	restore_all
456
457syscall_return_work:
458	j	syscall_exit_work
459
460syscall_trace_entry:
461	mv	r16, r10
462	mv	r4, r0
463	li	r5, 0
464	bl	do_syscall_trace
465
466	mv	r8, r16
467	lw	r4, [r0, PT_R4]		# Restore argument registers
468	lw	r5, [r0, PT_R5]
469	lw	r6, [r0, PT_R6]
470	lw	r7, [r0, PT_R7]
471	brl	r8
472
473	li	r8, -MAX_ERRNO - 1
474	sw	r8, [r0, PT_R7]		# set error flag
475
476	neg	r4, r4			# error
477	sw	r4, [r0, PT_R0]		# set flag for syscall
478					# restarting
4791:	sw	r4, [r0, PT_R2]		# result
480	j	syscall_exit
481
482illegal_syscall:
483	ldi	r4, -ENOSYS		# error
484	sw	r4, [r0, PT_ORIG_R4]
485	sw	r4, [r0, PT_R4]
486	ldi	r9, 1			# set error flag
487	sw	r9, [r0, PT_R7]
488	j	syscall_return
489
490ENTRY(sys_rt_sigreturn)
491	mv	r4, r0
492	la	r8, score_rt_sigreturn
493	br	r8
494