xref: /openbmc/linux/arch/csky/kernel/entry.S (revision 81de3bf3)
1/* SPDX-License-Identifier: GPL-2.0 */
2// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
3
4#include <linux/linkage.h>
5#include <abi/entry.h>
6#include <abi/pgtable-bits.h>
7#include <asm/errno.h>
8#include <asm/setup.h>
9#include <asm/unistd.h>
10#include <asm/asm-offsets.h>
11#include <linux/threads.h>
12#include <asm/setup.h>
13#include <asm/page.h>
14#include <asm/thread_info.h>
15
16#define PTE_INDX_MSK    0xffc
17#define PTE_INDX_SHIFT  10
18#define _PGDIR_SHIFT    22
19
20.macro	zero_fp
21#ifdef CONFIG_STACKTRACE
22	movi	r8, 0
23#endif
24.endm
25
26.macro tlbop_begin name, val0, val1, val2
27ENTRY(csky_\name)
28	mtcr    a3, ss2
29	mtcr    r6, ss3
30	mtcr    a2, ss4
31
32	RD_PGDR	r6
33	RD_MEH	a3
34#ifdef CONFIG_CPU_HAS_TLBI
35	tlbi.vaas a3
36	sync.is
37
38	btsti	a3, 31
39	bf	1f
40	RD_PGDR_K r6
411:
42#else
43	bgeni	a2, 31
44	WR_MCIR	a2
45	bgeni	a2, 25
46	WR_MCIR	a2
47#endif
48	bclri   r6, 0
49	lrw	a2, va_pa_offset
50	ld.w	a2, (a2, 0)
51	subu	r6, a2
52	bseti	r6, 31
53
54	mov     a2, a3
55	lsri    a2, _PGDIR_SHIFT
56	lsli    a2, 2
57	addu    r6, a2
58	ldw     r6, (r6)
59
60	lrw	a2, va_pa_offset
61	ld.w	a2, (a2, 0)
62	subu	r6, a2
63	bseti	r6, 31
64
65	lsri    a3, PTE_INDX_SHIFT
66	lrw     a2, PTE_INDX_MSK
67	and     a3, a2
68	addu    r6, a3
69	ldw     a3, (r6)
70
71	movi	a2, (_PAGE_PRESENT | \val0)
72	and     a3, a2
73	cmpne   a3, a2
74	bt	\name
75
76	/* First read/write the page, just update the flags */
77	ldw     a3, (r6)
78	bgeni   a2, PAGE_VALID_BIT
79	bseti   a2, PAGE_ACCESSED_BIT
80	bseti   a2, \val1
81	bseti   a2, \val2
82	or      a3, a2
83	stw     a3, (r6)
84
85	/* Some cpu tlb-hardrefill bypass the cache */
86#ifdef CONFIG_CPU_NEED_TLBSYNC
87	movi	a2, 0x22
88	bseti	a2, 6
89	mtcr	r6, cr22
90	mtcr	a2, cr17
91	sync
92#endif
93
94	mfcr    a3, ss2
95	mfcr    r6, ss3
96	mfcr    a2, ss4
97	rte
98\name:
99	mfcr    a3, ss2
100	mfcr    r6, ss3
101	mfcr    a2, ss4
102	SAVE_ALL 0
103.endm
104.macro tlbop_end is_write
105	zero_fp
106	RD_MEH	a2
107	psrset  ee, ie
108	mov     a0, sp
109	movi    a1, \is_write
110	jbsr    do_page_fault
111	jmpi    ret_from_exception
112.endm
113
114.text
115
116tlbop_begin tlbinvalidl, _PAGE_READ, PAGE_VALID_BIT, PAGE_ACCESSED_BIT
117tlbop_end 0
118
119tlbop_begin tlbinvalids, _PAGE_WRITE, PAGE_DIRTY_BIT, PAGE_MODIFIED_BIT
120tlbop_end 1
121
122tlbop_begin tlbmodified, _PAGE_WRITE, PAGE_DIRTY_BIT, PAGE_MODIFIED_BIT
123#ifndef CONFIG_CPU_HAS_LDSTEX
124jbsr csky_cmpxchg_fixup
125#endif
126tlbop_end 1
127
128ENTRY(csky_systemcall)
129	SAVE_ALL TRAP0_SIZE
130	zero_fp
131
132	psrset  ee, ie
133
134	lrw     r11, __NR_syscalls
135	cmphs   syscallid, r11		/* Check nr of syscall */
136	bt      ret_from_exception
137
138	lrw     r13, sys_call_table
139	ixw     r13, syscallid
140	ldw     r11, (r13)
141	cmpnei  r11, 0
142	bf      ret_from_exception
143
144	mov     r9, sp
145	bmaski  r10, THREAD_SHIFT
146	andn    r9, r10
147	ldw     r12, (r9, TINFO_FLAGS)
148	ANDI_R3	r12, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT)
149	cmpnei	r12, 0
150	bt      csky_syscall_trace
151#if defined(__CSKYABIV2__)
152	subi    sp, 8
153	stw  	r5, (sp, 0x4)
154	stw  	r4, (sp, 0x0)
155	jsr     r11                      /* Do system call */
156	addi 	sp, 8
157#else
158	jsr     r11
159#endif
160	stw     a0, (sp, LSAVE_A0)      /* Save return value */
161	jmpi    ret_from_exception
162
163csky_syscall_trace:
164	mov	a0, sp                  /* sp = pt_regs pointer */
165	jbsr	syscall_trace_enter
166	/* Prepare args before do system call */
167	ldw	a0, (sp, LSAVE_A0)
168	ldw	a1, (sp, LSAVE_A1)
169	ldw	a2, (sp, LSAVE_A2)
170	ldw	a3, (sp, LSAVE_A3)
171#if defined(__CSKYABIV2__)
172	subi	sp, 8
173	stw	r5, (sp, 0x4)
174	stw	r4, (sp, 0x0)
175#else
176	ldw	r6, (sp, LSAVE_A4)
177	ldw	r7, (sp, LSAVE_A5)
178#endif
179	jsr	r11                     /* Do system call */
180#if defined(__CSKYABIV2__)
181	addi	sp, 8
182#endif
183	stw	a0, (sp, LSAVE_A0)	/* Save return value */
184
185	mov     a0, sp                  /* right now, sp --> pt_regs */
186	jbsr    syscall_trace_exit
187	br	ret_from_exception
188
189ENTRY(ret_from_kernel_thread)
190	jbsr	schedule_tail
191	mov	a0, r10
192	jsr	r9
193	jbsr	ret_from_exception
194
195ENTRY(ret_from_fork)
196	jbsr	schedule_tail
197	mov	r9, sp
198	bmaski	r10, THREAD_SHIFT
199	andn	r9, r10
200	ldw	r12, (r9, TINFO_FLAGS)
201	ANDI_R3	r12, (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_TRACEPOINT | _TIF_SYSCALL_AUDIT)
202	cmpnei	r12, 0
203	bf	ret_from_exception
204	mov	a0, sp			/* sp = pt_regs pointer */
205	jbsr	syscall_trace_exit
206
207ret_from_exception:
208	ld	syscallid, (sp, LSAVE_PSR)
209	btsti	syscallid, 31
210	bt	1f
211
212	/*
213	 * Load address of current->thread_info, Then get address of task_struct
214	 * Get task_needreshed in task_struct
215	 */
216	mov	r9, sp
217	bmaski	r10, THREAD_SHIFT
218	andn	r9, r10
219
220	ldw	r12, (r9, TINFO_FLAGS)
221	andi	r12, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED)
222	cmpnei	r12, 0
223	bt	exit_work
2241:
225	RESTORE_ALL
226
227exit_work:
228	lrw	syscallid, ret_from_exception
229	mov	lr, syscallid
230
231	btsti	r12, TIF_NEED_RESCHED
232	bt	work_resched
233
234	mov	a0, sp
235	mov	a1, r12
236	jmpi	do_notify_resume
237
238work_resched:
239	jmpi	schedule
240
241ENTRY(csky_trap)
242	SAVE_ALL 0
243	zero_fp
244	psrset	ee
245	mov	a0, sp                 /* Push Stack pointer arg */
246	jbsr	trap_c                 /* Call C-level trap handler */
247	jmpi	ret_from_exception
248
249/*
250 * Prototype from libc for abiv1:
251 * register unsigned int __result asm("a0");
252 * asm( "trap 3" :"=r"(__result)::);
253 */
254ENTRY(csky_get_tls)
255	USPTOKSP
256
257	/* increase epc for continue */
258	mfcr	a0, epc
259	addi	a0, TRAP0_SIZE
260	mtcr	a0, epc
261
262	/* get current task thread_info with kernel 8K stack */
263	bmaski	a0, THREAD_SHIFT
264	not	a0
265	subi	sp, 1
266	and	a0, sp
267	addi	sp, 1
268
269	/* get tls */
270	ldw	a0, (a0, TINFO_TP_VALUE)
271
272	KSPTOUSP
273	rte
274
275ENTRY(csky_irq)
276	SAVE_ALL 0
277	zero_fp
278	psrset	ee
279
280#ifdef CONFIG_PREEMPT
281	mov	r9, sp			/* Get current stack  pointer */
282	bmaski	r10, THREAD_SHIFT
283	andn	r9, r10			/* Get thread_info */
284
285	/*
286	 * Get task_struct->stack.preempt_count for current,
287	 * and increase 1.
288	 */
289	ldw	r12, (r9, TINFO_PREEMPT)
290	addi	r12, 1
291	stw	r12, (r9, TINFO_PREEMPT)
292#endif
293
294	mov	a0, sp
295	jbsr	csky_do_IRQ
296
297#ifdef CONFIG_PREEMPT
298	subi	r12, 1
299	stw	r12, (r9, TINFO_PREEMPT)
300	cmpnei	r12, 0
301	bt	2f
302	ldw	r12, (r9, TINFO_FLAGS)
303	btsti	r12, TIF_NEED_RESCHED
304	bf	2f
305	jbsr	preempt_schedule_irq	/* irq en/disable is done inside */
306#endif
3072:
308	jmpi	ret_from_exception
309
310/*
311 * a0 =  prev task_struct *
312 * a1 =  next task_struct *
313 * a0 =  return next
314 */
315ENTRY(__switch_to)
316	lrw	a3, TASK_THREAD
317	addu	a3, a0
318
319	mfcr	a2, psr			/* Save PSR value */
320	stw	a2, (a3, THREAD_SR)	/* Save PSR in task struct */
321	bclri	a2, 6			/* Disable interrupts */
322	mtcr	a2, psr
323
324	SAVE_SWITCH_STACK
325
326	stw	sp, (a3, THREAD_KSP)
327
328	/* Set up next process to run */
329	lrw	a3, TASK_THREAD
330	addu	a3, a1
331
332	ldw	sp, (a3, THREAD_KSP)	/* Set next kernel sp */
333
334	ldw	a2, (a3, THREAD_SR)	/* Set next PSR */
335	mtcr	a2, psr
336
337#if  defined(__CSKYABIV2__)
338	addi	r7, a1, TASK_THREAD_INFO
339	ldw	tls, (r7, TINFO_TP_VALUE)
340#endif
341
342	RESTORE_SWITCH_STACK
343
344	rts
345ENDPROC(__switch_to)
346