xref: /kernel/linux/linux-6.6/arch/mips/kernel/entry.S (revision 62306a36)
162306a36Sopenharmony_ci/*
262306a36Sopenharmony_ci * This file is subject to the terms and conditions of the GNU General Public
362306a36Sopenharmony_ci * License.  See the file "COPYING" in the main directory of this archive
462306a36Sopenharmony_ci * for more details.
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
762306a36Sopenharmony_ci * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
862306a36Sopenharmony_ci * Copyright (C) 2001 MIPS Technologies, Inc.
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <asm/asm.h>
1262306a36Sopenharmony_ci#include <asm/asmmacro.h>
1362306a36Sopenharmony_ci#include <asm/compiler.h>
1462306a36Sopenharmony_ci#include <asm/irqflags.h>
1562306a36Sopenharmony_ci#include <asm/regdef.h>
1662306a36Sopenharmony_ci#include <asm/mipsregs.h>
1762306a36Sopenharmony_ci#include <asm/stackframe.h>
1862306a36Sopenharmony_ci#include <asm/isadep.h>
1962306a36Sopenharmony_ci#include <asm/thread_info.h>
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#ifndef CONFIG_PREEMPTION
2262306a36Sopenharmony_ci#define resume_kernel	restore_all
2362306a36Sopenharmony_ci#else
2462306a36Sopenharmony_ci#define __ret_from_irq	ret_from_exception
2562306a36Sopenharmony_ci#endif
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	.text
2862306a36Sopenharmony_ci	.align	5
2962306a36Sopenharmony_ci#ifndef CONFIG_PREEMPTION
3062306a36Sopenharmony_ciFEXPORT(ret_from_exception)
3162306a36Sopenharmony_ci	local_irq_disable			# preempt stop
3262306a36Sopenharmony_ci	b	__ret_from_irq
3362306a36Sopenharmony_ci#endif
3462306a36Sopenharmony_ciFEXPORT(ret_from_irq)
3562306a36Sopenharmony_ci	LONG_S	s0, TI_REGS($28)
3662306a36Sopenharmony_ciFEXPORT(__ret_from_irq)
3762306a36Sopenharmony_ci/*
3862306a36Sopenharmony_ci * We can be coming here from a syscall done in the kernel space,
3962306a36Sopenharmony_ci * e.g. a failed kernel_execve().
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_ciresume_userspace_check:
4262306a36Sopenharmony_ci	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
4362306a36Sopenharmony_ci	andi	t0, t0, KU_USER
4462306a36Sopenharmony_ci	beqz	t0, resume_kernel
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ciresume_userspace:
4762306a36Sopenharmony_ci	local_irq_disable		# make sure we dont miss an
4862306a36Sopenharmony_ci					# interrupt setting need_resched
4962306a36Sopenharmony_ci					# between sampling and return
5062306a36Sopenharmony_ci	LONG_L	a2, TI_FLAGS($28)	# current->work
5162306a36Sopenharmony_ci	andi	t0, a2, _TIF_WORK_MASK	# (ignoring syscall_trace)
5262306a36Sopenharmony_ci	bnez	t0, work_pending
5362306a36Sopenharmony_ci	j	restore_all
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#ifdef CONFIG_PREEMPTION
5662306a36Sopenharmony_ciresume_kernel:
5762306a36Sopenharmony_ci	local_irq_disable
5862306a36Sopenharmony_ci	lw	t0, TI_PRE_COUNT($28)
5962306a36Sopenharmony_ci	bnez	t0, restore_all
6062306a36Sopenharmony_ci	LONG_L	t0, TI_FLAGS($28)
6162306a36Sopenharmony_ci	andi	t1, t0, _TIF_NEED_RESCHED
6262306a36Sopenharmony_ci	beqz	t1, restore_all
6362306a36Sopenharmony_ci	LONG_L	t0, PT_STATUS(sp)		# Interrupts off?
6462306a36Sopenharmony_ci	andi	t0, 1
6562306a36Sopenharmony_ci	beqz	t0, restore_all
6662306a36Sopenharmony_ci	PTR_LA	ra, restore_all
6762306a36Sopenharmony_ci	j	preempt_schedule_irq
6862306a36Sopenharmony_ci#endif
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ciFEXPORT(ret_from_kernel_thread)
7162306a36Sopenharmony_ci	jal	schedule_tail		# a0 = struct task_struct *prev
7262306a36Sopenharmony_ci	move	a0, s1
7362306a36Sopenharmony_ci	jal	s0
7462306a36Sopenharmony_ci	j	syscall_exit
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ciFEXPORT(ret_from_fork)
7762306a36Sopenharmony_ci	jal	schedule_tail		# a0 = struct task_struct *prev
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ciFEXPORT(syscall_exit)
8062306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_RSEQ
8162306a36Sopenharmony_ci	move	a0, sp
8262306a36Sopenharmony_ci	jal	rseq_syscall
8362306a36Sopenharmony_ci#endif
8462306a36Sopenharmony_ci	local_irq_disable		# make sure need_resched and
8562306a36Sopenharmony_ci					# signals dont change between
8662306a36Sopenharmony_ci					# sampling and return
8762306a36Sopenharmony_ci	LONG_L	a2, TI_FLAGS($28)	# current->work
8862306a36Sopenharmony_ci	li	t0, _TIF_ALLWORK_MASK
8962306a36Sopenharmony_ci	and	t0, a2, t0
9062306a36Sopenharmony_ci	bnez	t0, syscall_exit_work
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_cirestore_all:				# restore full frame
9362306a36Sopenharmony_ci	.set	noat
9462306a36Sopenharmony_ci	RESTORE_TEMP
9562306a36Sopenharmony_ci	RESTORE_AT
9662306a36Sopenharmony_ci	RESTORE_STATIC
9762306a36Sopenharmony_cirestore_partial:		# restore partial frame
9862306a36Sopenharmony_ci#ifdef CONFIG_TRACE_IRQFLAGS
9962306a36Sopenharmony_ci	SAVE_STATIC
10062306a36Sopenharmony_ci	SAVE_AT
10162306a36Sopenharmony_ci	SAVE_TEMP
10262306a36Sopenharmony_ci	LONG_L	v0, PT_STATUS(sp)
10362306a36Sopenharmony_ci#if defined(CONFIG_CPU_R3000)
10462306a36Sopenharmony_ci	and	v0, ST0_IEP
10562306a36Sopenharmony_ci#else
10662306a36Sopenharmony_ci	and	v0, ST0_IE
10762306a36Sopenharmony_ci#endif
10862306a36Sopenharmony_ci	beqz	v0, 1f
10962306a36Sopenharmony_ci	jal	trace_hardirqs_on
11062306a36Sopenharmony_ci	b	2f
11162306a36Sopenharmony_ci1:	jal	trace_hardirqs_off
11262306a36Sopenharmony_ci2:
11362306a36Sopenharmony_ci	RESTORE_TEMP
11462306a36Sopenharmony_ci	RESTORE_AT
11562306a36Sopenharmony_ci	RESTORE_STATIC
11662306a36Sopenharmony_ci#endif
11762306a36Sopenharmony_ci	RESTORE_SOME
11862306a36Sopenharmony_ci	RESTORE_SP_AND_RET
11962306a36Sopenharmony_ci	.set	at
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ciwork_pending:
12262306a36Sopenharmony_ci	andi	t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
12362306a36Sopenharmony_ci	beqz	t0, work_notifysig
12462306a36Sopenharmony_ciwork_resched:
12562306a36Sopenharmony_ci	TRACE_IRQS_OFF
12662306a36Sopenharmony_ci	jal	schedule
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_ci	local_irq_disable		# make sure need_resched and
12962306a36Sopenharmony_ci					# signals dont change between
13062306a36Sopenharmony_ci					# sampling and return
13162306a36Sopenharmony_ci	LONG_L	a2, TI_FLAGS($28)
13262306a36Sopenharmony_ci	andi	t0, a2, _TIF_WORK_MASK	# is there any work to be done
13362306a36Sopenharmony_ci					# other than syscall tracing?
13462306a36Sopenharmony_ci	beqz	t0, restore_all
13562306a36Sopenharmony_ci	andi	t0, a2, _TIF_NEED_RESCHED
13662306a36Sopenharmony_ci	bnez	t0, work_resched
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ciwork_notifysig:				# deal with pending signals and
13962306a36Sopenharmony_ci					# notify-resume requests
14062306a36Sopenharmony_ci	move	a0, sp
14162306a36Sopenharmony_ci	li	a1, 0
14262306a36Sopenharmony_ci	jal	do_notify_resume	# a2 already loaded
14362306a36Sopenharmony_ci	j	resume_userspace_check
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ciFEXPORT(syscall_exit_partial)
14662306a36Sopenharmony_ci#ifdef CONFIG_DEBUG_RSEQ
14762306a36Sopenharmony_ci	move	a0, sp
14862306a36Sopenharmony_ci	jal	rseq_syscall
14962306a36Sopenharmony_ci#endif
15062306a36Sopenharmony_ci	local_irq_disable		# make sure need_resched doesn't
15162306a36Sopenharmony_ci					# change between and return
15262306a36Sopenharmony_ci	LONG_L	a2, TI_FLAGS($28)	# current->work
15362306a36Sopenharmony_ci	li	t0, _TIF_ALLWORK_MASK
15462306a36Sopenharmony_ci	and	t0, a2
15562306a36Sopenharmony_ci	beqz	t0, restore_partial
15662306a36Sopenharmony_ci	SAVE_STATIC
15762306a36Sopenharmony_cisyscall_exit_work:
15862306a36Sopenharmony_ci	LONG_L	t0, PT_STATUS(sp)		# returning to kernel mode?
15962306a36Sopenharmony_ci	andi	t0, t0, KU_USER
16062306a36Sopenharmony_ci	beqz	t0, resume_kernel
16162306a36Sopenharmony_ci	li	t0, _TIF_WORK_SYSCALL_EXIT
16262306a36Sopenharmony_ci	and	t0, a2			# a2 is preloaded with TI_FLAGS
16362306a36Sopenharmony_ci	beqz	t0, work_pending	# trace bit set?
16462306a36Sopenharmony_ci	local_irq_enable		# could let syscall_trace_leave()
16562306a36Sopenharmony_ci					# call schedule() instead
16662306a36Sopenharmony_ci	TRACE_IRQS_ON
16762306a36Sopenharmony_ci	move	a0, sp
16862306a36Sopenharmony_ci	jal	syscall_trace_leave
16962306a36Sopenharmony_ci	b	resume_userspace
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR5) || \
17262306a36Sopenharmony_ci    defined(CONFIG_CPU_MIPSR6) || defined(CONFIG_MIPS_MT)
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/*
17562306a36Sopenharmony_ci * MIPS32R2 Instruction Hazard Barrier - must be called
17662306a36Sopenharmony_ci *
17762306a36Sopenharmony_ci * For C code use the inline version named instruction_hazard().
17862306a36Sopenharmony_ci */
17962306a36Sopenharmony_ciLEAF(mips_ihb)
18062306a36Sopenharmony_ci	.set	MIPS_ISA_LEVEL_RAW
18162306a36Sopenharmony_ci	jr.hb	ra
18262306a36Sopenharmony_ci	nop
18362306a36Sopenharmony_ci	END(mips_ihb)
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci#endif /* CONFIG_CPU_MIPSR2 - CONFIG_CPU_MIPSR6 or CONFIG_MIPS_MT */
186