xref: /linux/arch/csky/kernel/entry.S (revision 31295a72b525721d10737260aea6918fb34607be)
1081860b9SGuo Ren/* SPDX-License-Identifier: GPL-2.0 */
2081860b9SGuo Ren// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
3081860b9SGuo Ren
4081860b9SGuo Ren#include <linux/linkage.h>
5081860b9SGuo Ren#include <abi/entry.h>
6081860b9SGuo Ren#include <abi/pgtable-bits.h>
7081860b9SGuo Ren#include <asm/errno.h>
8081860b9SGuo Ren#include <asm/setup.h>
9081860b9SGuo Ren#include <asm/unistd.h>
10081860b9SGuo Ren#include <asm/asm-offsets.h>
11081860b9SGuo Ren#include <linux/threads.h>
12081860b9SGuo Ren#include <asm/setup.h>
13081860b9SGuo Ren#include <asm/page.h>
14081860b9SGuo Ren#include <asm/thread_info.h>
15081860b9SGuo Ren
16081860b9SGuo Ren#define PTE_INDX_MSK    0xffc
17081860b9SGuo Ren#define PTE_INDX_SHIFT  10
18081860b9SGuo Ren#define _PGDIR_SHIFT    22
19081860b9SGuo Ren
20081860b9SGuo Ren.macro tlbop_begin name, val0, val1, val2
21081860b9SGuo RenENTRY(csky_\name)
22081860b9SGuo Ren	mtcr    a3, ss2
23081860b9SGuo Ren	mtcr    r6, ss3
24081860b9SGuo Ren	mtcr    a2, ss4
25081860b9SGuo Ren
26081860b9SGuo Ren	RD_PGDR	r6
27081860b9SGuo Ren	RD_MEH	a3
28081860b9SGuo Ren#ifdef CONFIG_CPU_HAS_TLBI
29081860b9SGuo Ren	tlbi.vaas a3
30081860b9SGuo Ren	sync.is
31081860b9SGuo Ren
32081860b9SGuo Ren	btsti	a3, 31
33081860b9SGuo Ren	bf	1f
34081860b9SGuo Ren	RD_PGDR_K r6
35081860b9SGuo Ren1:
36081860b9SGuo Ren#else
37081860b9SGuo Ren	bgeni	a2, 31
38081860b9SGuo Ren	WR_MCIR	a2
39081860b9SGuo Ren	bgeni	a2, 25
40081860b9SGuo Ren	WR_MCIR	a2
41081860b9SGuo Ren#endif
42081860b9SGuo Ren	bclri   r6, 0
43081860b9SGuo Ren	lrw	a2, PHYS_OFFSET
44081860b9SGuo Ren	subu	r6, a2
45081860b9SGuo Ren	bseti	r6, 31
46081860b9SGuo Ren
47081860b9SGuo Ren	mov     a2, a3
48081860b9SGuo Ren	lsri    a2, _PGDIR_SHIFT
49081860b9SGuo Ren	lsli    a2, 2
50081860b9SGuo Ren	addu    r6, a2
51081860b9SGuo Ren	ldw     r6, (r6)
52081860b9SGuo Ren
53081860b9SGuo Ren	lrw	a2, PHYS_OFFSET
54081860b9SGuo Ren	subu	r6, a2
55081860b9SGuo Ren	bseti	r6, 31
56081860b9SGuo Ren
57081860b9SGuo Ren	lsri    a3, PTE_INDX_SHIFT
58081860b9SGuo Ren	lrw     a2, PTE_INDX_MSK
59081860b9SGuo Ren	and     a3, a2
60081860b9SGuo Ren	addu    r6, a3
61081860b9SGuo Ren	ldw     a3, (r6)
62081860b9SGuo Ren
63081860b9SGuo Ren	movi	a2, (_PAGE_PRESENT | \val0)
64081860b9SGuo Ren	and     a3, a2
65081860b9SGuo Ren	cmpne   a3, a2
66081860b9SGuo Ren	bt	\name
67081860b9SGuo Ren
68081860b9SGuo Ren	/* First read/write the page, just update the flags */
69081860b9SGuo Ren	ldw     a3, (r6)
70081860b9SGuo Ren	bgeni   a2, PAGE_VALID_BIT
71081860b9SGuo Ren	bseti   a2, PAGE_ACCESSED_BIT
72081860b9SGuo Ren	bseti   a2, \val1
73081860b9SGuo Ren	bseti   a2, \val2
74081860b9SGuo Ren	or      a3, a2
75081860b9SGuo Ren	stw     a3, (r6)
76081860b9SGuo Ren
77081860b9SGuo Ren	/* Some cpu tlb-hardrefill bypass the cache */
78081860b9SGuo Ren#ifdef CONFIG_CPU_NEED_TLBSYNC
79081860b9SGuo Ren	movi	a2, 0x22
80081860b9SGuo Ren	bseti	a2, 6
81081860b9SGuo Ren	mtcr	r6, cr22
82081860b9SGuo Ren	mtcr	a2, cr17
83081860b9SGuo Ren	sync
84081860b9SGuo Ren#endif
85081860b9SGuo Ren
86081860b9SGuo Ren	mfcr    a3, ss2
87081860b9SGuo Ren	mfcr    r6, ss3
88081860b9SGuo Ren	mfcr    a2, ss4
89081860b9SGuo Ren	rte
90081860b9SGuo Ren\name:
91081860b9SGuo Ren	mfcr    a3, ss2
92081860b9SGuo Ren	mfcr    r6, ss3
93081860b9SGuo Ren	mfcr    a2, ss4
94081860b9SGuo Ren	SAVE_ALL EPC_KEEP
95081860b9SGuo Ren.endm
96081860b9SGuo Ren.macro tlbop_end is_write
97081860b9SGuo Ren	RD_MEH	a2
98081860b9SGuo Ren	psrset  ee, ie
99081860b9SGuo Ren	mov     a0, sp
100081860b9SGuo Ren	movi    a1, \is_write
101081860b9SGuo Ren	jbsr    do_page_fault
102081860b9SGuo Ren	movi    r11_sig, 0             /* r11 = 0, Not a syscall. */
103081860b9SGuo Ren	jmpi    ret_from_exception
104081860b9SGuo Ren.endm
105081860b9SGuo Ren
106081860b9SGuo Ren.text
107081860b9SGuo Ren
108081860b9SGuo Rentlbop_begin tlbinvalidl, _PAGE_READ, PAGE_VALID_BIT, PAGE_ACCESSED_BIT
109081860b9SGuo Rentlbop_end 0
110081860b9SGuo Ren
111081860b9SGuo Rentlbop_begin tlbinvalids, _PAGE_WRITE, PAGE_DIRTY_BIT, PAGE_MODIFIED_BIT
112081860b9SGuo Rentlbop_end 1
113081860b9SGuo Ren
114081860b9SGuo Rentlbop_begin tlbmodified, _PAGE_WRITE, PAGE_DIRTY_BIT, PAGE_MODIFIED_BIT
115081860b9SGuo Ren#ifndef CONFIG_CPU_HAS_LDSTEX
116081860b9SGuo Renjbsr csky_cmpxchg_fixup
117081860b9SGuo Ren#endif
118081860b9SGuo Rentlbop_end 1
119081860b9SGuo Ren
120081860b9SGuo RenENTRY(csky_systemcall)
121081860b9SGuo Ren	SAVE_ALL EPC_INCREASE
122081860b9SGuo Ren
123081860b9SGuo Ren	psrset  ee, ie
124081860b9SGuo Ren
125081860b9SGuo Ren	/* Stack frame for syscall, origin call set_esp0 */
126081860b9SGuo Ren	mov     r12, sp
127081860b9SGuo Ren
128081860b9SGuo Ren	bmaski  r11, 13
129081860b9SGuo Ren	andn    r12, r11
130081860b9SGuo Ren	bgeni   r11, 9
131081860b9SGuo Ren	addi    r11, 32
132081860b9SGuo Ren	addu    r12, r11
133081860b9SGuo Ren	st      sp, (r12, 0)
134081860b9SGuo Ren
135081860b9SGuo Ren	lrw     r11, __NR_syscalls
136081860b9SGuo Ren	cmphs   syscallid, r11		/* Check nr of syscall */
137081860b9SGuo Ren	bt      ret_from_exception
138081860b9SGuo Ren
139081860b9SGuo Ren	lrw     r13, sys_call_table
140081860b9SGuo Ren	ixw     r13, syscallid
141081860b9SGuo Ren	ldw     r11, (r13)
142081860b9SGuo Ren	cmpnei  r11, 0
143081860b9SGuo Ren	bf      ret_from_exception
144081860b9SGuo Ren
145081860b9SGuo Ren	mov     r9, sp
146081860b9SGuo Ren	bmaski  r10, THREAD_SHIFT
147081860b9SGuo Ren	andn    r9, r10
148081860b9SGuo Ren	ldw     r8, (r9, TINFO_FLAGS)
149081860b9SGuo Ren	btsti   r8, TIF_SYSCALL_TRACE
150081860b9SGuo Ren	bt      1f
151081860b9SGuo Ren#if defined(__CSKYABIV2__)
152081860b9SGuo Ren	subi    sp, 8
153081860b9SGuo Ren	stw  	r5, (sp, 0x4)
154081860b9SGuo Ren	stw  	r4, (sp, 0x0)
155081860b9SGuo Ren	jsr     r11                      /* Do system call */
156081860b9SGuo Ren	addi 	sp, 8
157081860b9SGuo Ren#else
158081860b9SGuo Ren	jsr     r11
159081860b9SGuo Ren#endif
160081860b9SGuo Ren	stw     a0, (sp, LSAVE_A0)      /* Save return value */
161081860b9SGuo Ren	jmpi    ret_from_exception
162081860b9SGuo Ren
163081860b9SGuo Ren1:
164081860b9SGuo Ren	movi	a0, 0                   /* enter system call */
165081860b9SGuo Ren	mov	a1, sp                  /* sp = pt_regs pointer */
166081860b9SGuo Ren	jbsr	syscall_trace
167081860b9SGuo Ren	/* Prepare args before do system call */
168081860b9SGuo Ren	ldw	a0, (sp, LSAVE_A0)
169081860b9SGuo Ren	ldw	a1, (sp, LSAVE_A1)
170081860b9SGuo Ren	ldw	a2, (sp, LSAVE_A2)
171081860b9SGuo Ren	ldw	a3, (sp, LSAVE_A3)
172081860b9SGuo Ren#if defined(__CSKYABIV2__)
173081860b9SGuo Ren	subi	sp, 8
174081860b9SGuo Ren	stw	r5, (sp, 0x4)
175081860b9SGuo Ren	stw	r4, (sp, 0x0)
176081860b9SGuo Ren#else
177081860b9SGuo Ren	ldw	r6, (sp, LSAVE_A4)
178081860b9SGuo Ren	ldw	r7, (sp, LSAVE_A5)
179081860b9SGuo Ren#endif
180081860b9SGuo Ren	jsr	r11                     /* Do system call */
181081860b9SGuo Ren#if defined(__CSKYABIV2__)
182081860b9SGuo Ren	addi	sp, 8
183081860b9SGuo Ren#endif
184081860b9SGuo Ren	stw	a0, (sp, LSAVE_A0)	/* Save return value */
185081860b9SGuo Ren
186081860b9SGuo Ren	movi    a0, 1                   /* leave system call */
187*31295a72SGuo Ren	mov     a1, sp                  /* right now, sp --> pt_regs */
188081860b9SGuo Ren	jbsr    syscall_trace
189*31295a72SGuo Ren	br	ret_from_exception
190081860b9SGuo Ren
191081860b9SGuo RenENTRY(ret_from_kernel_thread)
192081860b9SGuo Ren	jbsr	schedule_tail
193081860b9SGuo Ren	mov	a0, r8
194081860b9SGuo Ren	jsr	r9
195081860b9SGuo Ren	jbsr	ret_from_exception
196081860b9SGuo Ren
197081860b9SGuo RenENTRY(ret_from_fork)
198081860b9SGuo Ren	jbsr	schedule_tail
199081860b9SGuo Ren	mov	r9, sp
200081860b9SGuo Ren	bmaski	r10, THREAD_SHIFT
201081860b9SGuo Ren	andn	r9, r10
202081860b9SGuo Ren	ldw	r8, (r9, TINFO_FLAGS)
203081860b9SGuo Ren	movi	r11_sig, 1
204081860b9SGuo Ren	btsti	r8, TIF_SYSCALL_TRACE
205081860b9SGuo Ren	bf	3f
206081860b9SGuo Ren	movi	a0, 1
207081860b9SGuo Ren	mov	a1, sp			/* sp = pt_regs pointer */
208081860b9SGuo Ren	jbsr	syscall_trace
209081860b9SGuo Ren3:
210081860b9SGuo Ren	jbsr	ret_from_exception
211081860b9SGuo Ren
212081860b9SGuo Renret_from_exception:
213081860b9SGuo Ren	ld	syscallid, (sp, LSAVE_PSR)
214081860b9SGuo Ren	btsti	syscallid, 31
215081860b9SGuo Ren	bt	1f
216081860b9SGuo Ren
217081860b9SGuo Ren	/*
218081860b9SGuo Ren	 * Load address of current->thread_info, Then get address of task_struct
219081860b9SGuo Ren	 * Get task_needreshed in task_struct
220081860b9SGuo Ren	 */
221081860b9SGuo Ren	mov	r9, sp
222081860b9SGuo Ren	bmaski	r10, THREAD_SHIFT
223081860b9SGuo Ren	andn	r9, r10
224081860b9SGuo Ren
225081860b9SGuo Renresume_userspace:
226081860b9SGuo Ren	ldw	r8, (r9, TINFO_FLAGS)
227081860b9SGuo Ren	andi	r8, (_TIF_SIGPENDING | _TIF_NOTIFY_RESUME | _TIF_NEED_RESCHED)
228081860b9SGuo Ren	cmpnei	r8, 0
229081860b9SGuo Ren	bt	exit_work
230081860b9SGuo Ren1:  RESTORE_ALL
231081860b9SGuo Ren
232081860b9SGuo Renexit_work:
233081860b9SGuo Ren	mov	a0, sp			/* Stack address is arg[0] */
234081860b9SGuo Ren	jbsr	set_esp0		/* Call C level */
235081860b9SGuo Ren	btsti	r8, TIF_NEED_RESCHED
236081860b9SGuo Ren	bt	work_resched
237081860b9SGuo Ren	/* If thread_info->flag is empty, RESTORE_ALL */
238081860b9SGuo Ren	cmpnei	r8, 0
239081860b9SGuo Ren	bf	1b
240081860b9SGuo Ren	mov	a1, sp
241081860b9SGuo Ren	mov	a0, r8
242081860b9SGuo Ren	mov	a2, r11_sig		/* syscall? */
243081860b9SGuo Ren	btsti	r8, TIF_SIGPENDING	/* delivering a signal? */
244081860b9SGuo Ren	/* prevent further restarts(set r11 = 0) */
245081860b9SGuo Ren	clrt	r11_sig
246081860b9SGuo Ren	jbsr	do_notify_resume	/* do signals */
247081860b9SGuo Ren	br	resume_userspace
248081860b9SGuo Ren
249081860b9SGuo Renwork_resched:
250081860b9SGuo Ren	lrw	syscallid, ret_from_exception
251081860b9SGuo Ren	mov	r15, syscallid		/* Return address in link */
252081860b9SGuo Ren	jmpi	schedule
253081860b9SGuo Ren
254081860b9SGuo RenENTRY(sys_rt_sigreturn)
255081860b9SGuo Ren	movi	r11_sig, 0
256081860b9SGuo Ren	jmpi	do_rt_sigreturn
257081860b9SGuo Ren
258081860b9SGuo RenENTRY(csky_trap)
259081860b9SGuo Ren	SAVE_ALL EPC_KEEP
260081860b9SGuo Ren	psrset	ee
261081860b9SGuo Ren	movi	r11_sig, 0             /* r11 = 0, Not a syscall. */
262081860b9SGuo Ren	mov	a0, sp                 /* Push Stack pointer arg */
263081860b9SGuo Ren	jbsr	trap_c                 /* Call C-level trap handler */
264081860b9SGuo Ren	jmpi	ret_from_exception
265081860b9SGuo Ren
266081860b9SGuo Ren/*
267081860b9SGuo Ren * Prototype from libc for abiv1:
268081860b9SGuo Ren * register unsigned int __result asm("a0");
269081860b9SGuo Ren * asm( "trap 3" :"=r"(__result)::);
270081860b9SGuo Ren */
271081860b9SGuo RenENTRY(csky_get_tls)
272081860b9SGuo Ren	USPTOKSP
273081860b9SGuo Ren
274081860b9SGuo Ren	/* increase epc for continue */
275081860b9SGuo Ren	mfcr	a0, epc
276081860b9SGuo Ren	INCTRAP	a0
277081860b9SGuo Ren	mtcr	a0, epc
278081860b9SGuo Ren
279081860b9SGuo Ren	/* get current task thread_info with kernel 8K stack */
280081860b9SGuo Ren	bmaski	a0, THREAD_SHIFT
281081860b9SGuo Ren	not	a0
282081860b9SGuo Ren	subi	sp, 1
283081860b9SGuo Ren	and	a0, sp
284081860b9SGuo Ren	addi	sp, 1
285081860b9SGuo Ren
286081860b9SGuo Ren	/* get tls */
287081860b9SGuo Ren	ldw	a0, (a0, TINFO_TP_VALUE)
288081860b9SGuo Ren
289081860b9SGuo Ren	KSPTOUSP
290081860b9SGuo Ren	rte
291081860b9SGuo Ren
292081860b9SGuo RenENTRY(csky_irq)
293081860b9SGuo Ren	SAVE_ALL EPC_KEEP
294081860b9SGuo Ren	psrset	ee
295081860b9SGuo Ren	movi	r11_sig, 0		/* r11 = 0, Not a syscall. */
296081860b9SGuo Ren
297081860b9SGuo Ren#ifdef CONFIG_PREEMPT
298081860b9SGuo Ren	mov	r9, sp			/* Get current stack  pointer */
299081860b9SGuo Ren	bmaski	r10, THREAD_SHIFT
300081860b9SGuo Ren	andn	r9, r10			/* Get thread_info */
301081860b9SGuo Ren
302081860b9SGuo Ren	/*
303081860b9SGuo Ren	 * Get task_struct->stack.preempt_count for current,
304081860b9SGuo Ren	 * and increase 1.
305081860b9SGuo Ren	 */
306081860b9SGuo Ren	ldw	r8, (r9, TINFO_PREEMPT)
307081860b9SGuo Ren	addi	r8, 1
308081860b9SGuo Ren	stw	r8, (r9, TINFO_PREEMPT)
309081860b9SGuo Ren#endif
310081860b9SGuo Ren
311081860b9SGuo Ren	mov	a0, sp
312081860b9SGuo Ren	jbsr	csky_do_IRQ
313081860b9SGuo Ren
314081860b9SGuo Ren#ifdef CONFIG_PREEMPT
315081860b9SGuo Ren	subi	r8, 1
316081860b9SGuo Ren	stw	r8, (r9, TINFO_PREEMPT)
317081860b9SGuo Ren	cmpnei	r8, 0
318081860b9SGuo Ren	bt	2f
319081860b9SGuo Ren	ldw	r8, (r9, TINFO_FLAGS)
320081860b9SGuo Ren	btsti	r8, TIF_NEED_RESCHED
321081860b9SGuo Ren	bf	2f
322081860b9SGuo Ren1:
323081860b9SGuo Ren	jbsr	preempt_schedule_irq	/* irq en/disable is done inside */
324081860b9SGuo Ren	ldw	r7, (r9, TINFO_FLAGS)	/* get new tasks TI_FLAGS */
325081860b9SGuo Ren	btsti	r7, TIF_NEED_RESCHED
326081860b9SGuo Ren	bt	1b			/* go again */
327081860b9SGuo Ren#endif
328081860b9SGuo Ren2:
329081860b9SGuo Ren	jmpi	ret_from_exception
330081860b9SGuo Ren
331081860b9SGuo Ren/*
332081860b9SGuo Ren * a0 =  prev task_struct *
333081860b9SGuo Ren * a1 =  next task_struct *
334081860b9SGuo Ren * a0 =  return next
335081860b9SGuo Ren */
336081860b9SGuo RenENTRY(__switch_to)
337081860b9SGuo Ren	lrw	a3, TASK_THREAD
338081860b9SGuo Ren	addu	a3, a0
339081860b9SGuo Ren
340081860b9SGuo Ren	mfcr	a2, psr			/* Save PSR value */
341081860b9SGuo Ren	stw	a2, (a3, THREAD_SR)	/* Save PSR in task struct */
342081860b9SGuo Ren	bclri	a2, 6			/* Disable interrupts */
343081860b9SGuo Ren	mtcr	a2, psr
344081860b9SGuo Ren
345081860b9SGuo Ren	SAVE_SWITCH_STACK
346081860b9SGuo Ren
347081860b9SGuo Ren	stw	sp, (a3, THREAD_KSP)
348081860b9SGuo Ren
349081860b9SGuo Ren#ifdef CONFIG_CPU_HAS_HILO
350081860b9SGuo Ren	lrw	r10, THREAD_DSPHI
351081860b9SGuo Ren	add	r10, a3
352081860b9SGuo Ren	mfhi	r6
353081860b9SGuo Ren	mflo	r7
354081860b9SGuo Ren	stw	r6, (r10, 0)		/* THREAD_DSPHI */
355081860b9SGuo Ren	stw	r7, (r10, 4)		/* THREAD_DSPLO */
356081860b9SGuo Ren	mfcr	r6, cr14
357081860b9SGuo Ren	stw	r6, (r10, 8)		/* THREAD_DSPCSR */
358081860b9SGuo Ren#endif
359081860b9SGuo Ren
360081860b9SGuo Ren	/* Set up next process to run */
361081860b9SGuo Ren	lrw	a3, TASK_THREAD
362081860b9SGuo Ren	addu	a3, a1
363081860b9SGuo Ren
364081860b9SGuo Ren	ldw	sp, (a3, THREAD_KSP)	/* Set next kernel sp */
365081860b9SGuo Ren
366081860b9SGuo Ren#ifdef CONFIG_CPU_HAS_HILO
367081860b9SGuo Ren	lrw	r10, THREAD_DSPHI
368081860b9SGuo Ren	add	r10, a3
369081860b9SGuo Ren	ldw	r6, (r10, 8)		/* THREAD_DSPCSR */
370081860b9SGuo Ren	mtcr	r6, cr14
371081860b9SGuo Ren	ldw	r6, (r10, 0)		/* THREAD_DSPHI */
372081860b9SGuo Ren	ldw	r7, (r10, 4)		/* THREAD_DSPLO */
373081860b9SGuo Ren	mthi	r6
374081860b9SGuo Ren	mtlo	r7
375081860b9SGuo Ren#endif
376081860b9SGuo Ren
377081860b9SGuo Ren	ldw	a2, (a3, THREAD_SR)	/* Set next PSR */
378081860b9SGuo Ren	mtcr	a2, psr
379081860b9SGuo Ren
380081860b9SGuo Ren#if  defined(__CSKYABIV2__)
381081860b9SGuo Ren	addi	r7, a1, TASK_THREAD_INFO
382081860b9SGuo Ren	ldw	tls, (r7, TINFO_TP_VALUE)
383081860b9SGuo Ren#endif
384081860b9SGuo Ren
385081860b9SGuo Ren	RESTORE_SWITCH_STACK
386081860b9SGuo Ren
387081860b9SGuo Ren	rts
388081860b9SGuo RenENDPROC(__switch_to)
389