xref: /openbmc/linux/arch/csky/kernel/entry.S (revision fed8b7e3)
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 tlbop_begin name, val0, val1, val2
21ENTRY(csky_\name)
22	mtcr    a3, ss2
23	mtcr    r6, ss3
24	mtcr    a2, ss4
25
26	RD_PGDR	r6
27	RD_MEH	a3
28#ifdef CONFIG_CPU_HAS_TLBI
29	tlbi.vaas a3
30	sync.is
31
32	btsti	a3, 31
33	bf	1f
34	RD_PGDR_K r6
351:
36#else
37	bgeni	a2, 31
38	WR_MCIR	a2
39	bgeni	a2, 25
40	WR_MCIR	a2
41#endif
42	bclri   r6, 0
43	lrw	a2, PHYS_OFFSET
44	subu	r6, a2
45	bseti	r6, 31
46
47	mov     a2, a3
48	lsri    a2, _PGDIR_SHIFT
49	lsli    a2, 2
50	addu    r6, a2
51	ldw     r6, (r6)
52
53	lrw	a2, PHYS_OFFSET
54	subu	r6, a2
55	bseti	r6, 31
56
57	lsri    a3, PTE_INDX_SHIFT
58	lrw     a2, PTE_INDX_MSK
59	and     a3, a2
60	addu    r6, a3
61	ldw     a3, (r6)
62
63	movi	a2, (_PAGE_PRESENT | \val0)
64	and     a3, a2
65	cmpne   a3, a2
66	bt	\name
67
68	/* First read/write the page, just update the flags */
69	ldw     a3, (r6)
70	bgeni   a2, PAGE_VALID_BIT
71	bseti   a2, PAGE_ACCESSED_BIT
72	bseti   a2, \val1
73	bseti   a2, \val2
74	or      a3, a2
75	stw     a3, (r6)
76
77	/* Some cpu tlb-hardrefill bypass the cache */
78#ifdef CONFIG_CPU_NEED_TLBSYNC
79	movi	a2, 0x22
80	bseti	a2, 6
81	mtcr	r6, cr22
82	mtcr	a2, cr17
83	sync
84#endif
85
86	mfcr    a3, ss2
87	mfcr    r6, ss3
88	mfcr    a2, ss4
89	rte
90\name:
91	mfcr    a3, ss2
92	mfcr    r6, ss3
93	mfcr    a2, ss4
94	SAVE_ALL EPC_KEEP
95.endm
96.macro tlbop_end is_write
97	RD_MEH	a2
98	psrset  ee, ie
99	mov     a0, sp
100	movi    a1, \is_write
101	jbsr    do_page_fault
102	movi    r11_sig, 0             /* r11 = 0, Not a syscall. */
103	jmpi    ret_from_exception
104.endm
105
106.text
107
108tlbop_begin tlbinvalidl, _PAGE_READ, PAGE_VALID_BIT, PAGE_ACCESSED_BIT
109tlbop_end 0
110
111tlbop_begin tlbinvalids, _PAGE_WRITE, PAGE_DIRTY_BIT, PAGE_MODIFIED_BIT
112tlbop_end 1
113
114tlbop_begin tlbmodified, _PAGE_WRITE, PAGE_DIRTY_BIT, PAGE_MODIFIED_BIT
115#ifndef CONFIG_CPU_HAS_LDSTEX
116jbsr csky_cmpxchg_fixup
117#endif
118tlbop_end 1
119
120ENTRY(csky_systemcall)
121	SAVE_ALL EPC_INCREASE
122
123	psrset  ee, ie
124
125	/* Stack frame for syscall, origin call set_esp0 */
126	mov     r12, sp
127
128	bmaski  r11, 13
129	andn    r12, r11
130	bgeni   r11, 9
131	addi    r11, 32
132	addu    r12, r11
133	st      sp, (r12, 0)
134
135	lrw     r11, __NR_syscalls
136	cmphs   syscallid, r11		/* Check nr of syscall */
137	bt      ret_from_exception
138
139	lrw     r13, sys_call_table
140	ixw     r13, syscallid
141	ldw     r11, (r13)
142	cmpnei  r11, 0
143	bf      ret_from_exception
144
145	mov     r9, sp
146	bmaski  r10, THREAD_SHIFT
147	andn    r9, r10
148	ldw     r8, (r9, TINFO_FLAGS)
149	btsti   r8, TIF_SYSCALL_TRACE
150	bt      1f
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
1631:
164	movi	a0, 0                   /* enter system call */
165	mov	a1, sp                  /* sp = pt_regs pointer */
166	jbsr	syscall_trace
167	/* Prepare args before do system call */
168	ldw	a0, (sp, LSAVE_A0)
169	ldw	a1, (sp, LSAVE_A1)
170	ldw	a2, (sp, LSAVE_A2)
171	ldw	a3, (sp, LSAVE_A3)
172#if defined(__CSKYABIV2__)
173	subi	sp, 8
174	stw	r5, (sp, 0x4)
175	stw	r4, (sp, 0x0)
176#else
177	ldw	r6, (sp, LSAVE_A4)
178	ldw	r7, (sp, LSAVE_A5)
179#endif
180	jsr	r11                     /* Do system call */
181#if defined(__CSKYABIV2__)
182	addi	sp, 8
183#endif
184	stw	a0, (sp, LSAVE_A0)	/* Save return value */
185
186	movi	a0, 1			/* leave system call */
187	mov	a1, sp			/* sp = pt_regs pointer */
188	jbsr	syscall_trace
189
190syscall_exit_work:
191	ld	syscallid, (sp, LSAVE_PSR)
192	btsti	syscallid, 31
193	bt	2f
194
195	jmpi	resume_userspace
196
1972:      RESTORE_ALL
198
199ENTRY(ret_from_kernel_thread)
200	jbsr	schedule_tail
201	mov	a0, r8
202	jsr	r9
203	jbsr	ret_from_exception
204
205ENTRY(ret_from_fork)
206	jbsr	schedule_tail
207	mov	r9, sp
208	bmaski	r10, THREAD_SHIFT
209	andn	r9, r10
210	ldw	r8, (r9, TINFO_FLAGS)
211	movi	r11_sig, 1
212	btsti	r8, TIF_SYSCALL_TRACE
213	bf	3f
214	movi	a0, 1
215	mov	a1, sp			/* sp = pt_regs pointer */
216	jbsr	syscall_trace
2173:
218	jbsr	ret_from_exception
219
220ret_from_exception:
221	ld	syscallid, (sp, LSAVE_PSR)
222	btsti	syscallid, 31
223	bt	1f
224
225	/*
226	 * Load address of current->thread_info, Then get address of task_struct
227	 * Get task_needreshed in task_struct
228	 */
229	mov	r9, sp
230	bmaski	r10, THREAD_SHIFT
231	andn	r9, r10
232
233resume_userspace:
234	ldw	r8, (r9, TINFO_FLAGS)
235	andi	r8, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED)
236	cmpnei	r8, 0
237	bt	exit_work
2381:  RESTORE_ALL
239
240exit_work:
241	mov	a0, sp			/* Stack address is arg[0] */
242	jbsr	set_esp0		/* Call C level */
243	btsti	r8, TIF_NEED_RESCHED
244	bt	work_resched
245	/* If thread_info->flag is empty, RESTORE_ALL */
246	cmpnei	r8, 0
247	bf	1b
248	mov	a1, sp
249	mov	a0, r8
250	mov	a2, r11_sig		/* syscall? */
251	btsti	r8, TIF_SIGPENDING	/* delivering a signal? */
252	/* prevent further restarts(set r11 = 0) */
253	clrt	r11_sig
254	jbsr	do_notify_resume	/* do signals */
255	br	resume_userspace
256
257work_resched:
258	lrw	syscallid, ret_from_exception
259	mov	r15, syscallid		/* Return address in link */
260	jmpi	schedule
261
262ENTRY(sys_rt_sigreturn)
263	movi	r11_sig, 0
264	jmpi	do_rt_sigreturn
265
266ENTRY(csky_trap)
267	SAVE_ALL EPC_KEEP
268	psrset	ee
269	movi	r11_sig, 0             /* r11 = 0, Not a syscall. */
270	mov	a0, sp                 /* Push Stack pointer arg */
271	jbsr	trap_c                 /* Call C-level trap handler */
272	jmpi	ret_from_exception
273
274/*
275 * Prototype from libc for abiv1:
276 * register unsigned int __result asm("a0");
277 * asm( "trap 3" :"=r"(__result)::);
278 */
279ENTRY(csky_get_tls)
280	USPTOKSP
281
282	/* increase epc for continue */
283	mfcr	a0, epc
284	INCTRAP	a0
285	mtcr	a0, epc
286
287	/* get current task thread_info with kernel 8K stack */
288	bmaski	a0, THREAD_SHIFT
289	not	a0
290	subi	sp, 1
291	and	a0, sp
292	addi	sp, 1
293
294	/* get tls */
295	ldw	a0, (a0, TINFO_TP_VALUE)
296
297	KSPTOUSP
298	rte
299
300ENTRY(csky_irq)
301	SAVE_ALL EPC_KEEP
302	psrset	ee
303	movi	r11_sig, 0		/* r11 = 0, Not a syscall. */
304
305#ifdef CONFIG_PREEMPT
306	mov	r9, sp			/* Get current stack  pointer */
307	bmaski	r10, THREAD_SHIFT
308	andn	r9, r10			/* Get thread_info */
309
310	/*
311	 * Get task_struct->stack.preempt_count for current,
312	 * and increase 1.
313	 */
314	ldw	r8, (r9, TINFO_PREEMPT)
315	addi	r8, 1
316	stw	r8, (r9, TINFO_PREEMPT)
317#endif
318
319	mov	a0, sp
320	jbsr	csky_do_IRQ
321
322#ifdef CONFIG_PREEMPT
323	subi	r8, 1
324	stw	r8, (r9, TINFO_PREEMPT)
325	cmpnei	r8, 0
326	bt	2f
327	ldw	r8, (r9, TINFO_FLAGS)
328	btsti	r8, TIF_NEED_RESCHED
329	bf	2f
3301:
331	jbsr	preempt_schedule_irq	/* irq en/disable is done inside */
332	ldw	r7, (r9, TINFO_FLAGS)	/* get new tasks TI_FLAGS */
333	btsti	r7, TIF_NEED_RESCHED
334	bt	1b			/* go again */
335#endif
3362:
337	jmpi	ret_from_exception
338
339/*
340 * a0 =  prev task_struct *
341 * a1 =  next task_struct *
342 * a0 =  return next
343 */
344ENTRY(__switch_to)
345	lrw	a3, TASK_THREAD
346	addu	a3, a0
347
348	mfcr	a2, psr			/* Save PSR value */
349	stw	a2, (a3, THREAD_SR)	/* Save PSR in task struct */
350	bclri	a2, 6			/* Disable interrupts */
351	mtcr	a2, psr
352
353	SAVE_SWITCH_STACK
354
355	stw	sp, (a3, THREAD_KSP)
356
357#ifdef CONFIG_CPU_HAS_HILO
358	lrw	r10, THREAD_DSPHI
359	add	r10, a3
360	mfhi	r6
361	mflo	r7
362	stw	r6, (r10, 0)		/* THREAD_DSPHI */
363	stw	r7, (r10, 4)		/* THREAD_DSPLO */
364	mfcr	r6, cr14
365	stw	r6, (r10, 8)		/* THREAD_DSPCSR */
366#endif
367
368	/* Set up next process to run */
369	lrw	a3, TASK_THREAD
370	addu	a3, a1
371
372	ldw	sp, (a3, THREAD_KSP)	/* Set next kernel sp */
373
374#ifdef CONFIG_CPU_HAS_HILO
375	lrw	r10, THREAD_DSPHI
376	add	r10, a3
377	ldw	r6, (r10, 8)		/* THREAD_DSPCSR */
378	mtcr	r6, cr14
379	ldw	r6, (r10, 0)		/* THREAD_DSPHI */
380	ldw	r7, (r10, 4)		/* THREAD_DSPLO */
381	mthi	r6
382	mtlo	r7
383#endif
384
385	ldw	a2, (a3, THREAD_SR)	/* Set next PSR */
386	mtcr	a2, psr
387
388#if  defined(__CSKYABIV2__)
389	addi	r7, a1, TASK_THREAD_INFO
390	ldw	tls, (r7, TINFO_TP_VALUE)
391#endif
392
393	RESTORE_SWITCH_STACK
394
395	rts
396ENDPROC(__switch_to)
397