Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7c151d3d authored by Markos Chandras's avatar Markos Chandras
Browse files

MIPS: Make use of the ERETNC instruction on MIPS R6



The ERETNC instruction, introduced in MIPS R5, is similar to the ERET
one, except it does not clear the LLB bit in the LLADDR register.
This feature is necessary to safely emulate R2 LL/SC instructions.
However, on context switches, we need to clear the LLAddr/LLB bit
in order to make sure that an SC instruction from the new thread
will never succeed if it happens to interrupt an LL operation on the
same address from the previous thread.

Signed-off-by: default avatarMarkos Chandras <markos.chandras@imgtec.com>
parent b0a668fb
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -75,9 +75,12 @@ do { \
#endif

#define __clear_software_ll_bit()					\
do {									\
do {	if (cpu_has_rw_llb) {						\
		write_c0_lladdr(0);					\
	} else {							\
		if (!__builtin_constant_p(cpu_has_llsc) || !cpu_has_llsc)\
			ll_bit = 0;					\
	}								\
} while (0)

#define switch_to(prev, next, last)					\
+1 −1
Original line number Diff line number Diff line
@@ -28,7 +28,7 @@ struct thread_info {
	unsigned long		tp_value;	/* thread pointer */
	__u32			cpu;		/* current CPU */
	int			preempt_count;	/* 0 => preemptable, <0 => BUG */

	int			r2_emul_return; /* 1 => Returning from R2 emulator */
	mm_segment_t		addr_limit;	/*
						 * thread address space limit:
						 * 0x7fffffff for user-thead
+1 −0
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ void output_thread_info_defines(void)
	OFFSET(TI_TP_VALUE, thread_info, tp_value);
	OFFSET(TI_CPU, thread_info, cpu);
	OFFSET(TI_PRE_COUNT, thread_info, preempt_count);
	OFFSET(TI_R2_EMUL_RET, thread_info, r2_emul_return);
	OFFSET(TI_ADDR_LIMIT, thread_info, addr_limit);
	OFFSET(TI_RESTART_BLOCK, thread_info, restart_block);
	OFFSET(TI_REGS, thread_info, regs);
+18 −0
Original line number Diff line number Diff line
@@ -46,6 +46,11 @@ resume_userspace:
	local_irq_disable		# make sure we dont miss an
					# interrupt setting need_resched
					# between sampling and return
#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
	lw	k0, TI_R2_EMUL_RET($28)
	bnez	k0, restore_all_from_r2_emul
#endif

	LONG_L	a2, TI_FLAGS($28)	# current->work
	andi	t0, a2, _TIF_WORK_MASK	# (ignoring syscall_trace)
	bnez	t0, work_pending
@@ -114,6 +119,19 @@ restore_partial: # restore partial frame
	RESTORE_SP_AND_RET
	.set	at

#ifdef CONFIG_MIPSR2_TO_R6_EMULATOR
restore_all_from_r2_emul:			# restore full frame
	.set	noat
	sw	zero, TI_R2_EMUL_RET($28)	# reset it
	RESTORE_TEMP
	RESTORE_AT
	RESTORE_STATIC
	RESTORE_SOME
	LONG_L	sp, PT_R29(sp)
	eretnc
	.set	at
#endif

work_pending:
	andi	t0, a2, _TIF_NEED_RESCHED # a2 is preloaded with TI_FLAGS
	beqz	t0, work_notifysig
+2 −0
Original line number Diff line number Diff line
@@ -1039,12 +1039,14 @@ asmlinkage void do_ri(struct pt_regs *regs)
			switch (status) {
			case 0:
			case SIGEMT:
				task_thread_info(current)->r2_emul_return = 1;
				return;
			case SIGILL:
				goto no_r2_instr;
			default:
				process_fpemu_return(status,
						     &current->thread.cp0_baduaddr);
				task_thread_info(current)->r2_emul_return = 1;
				return;
			}
		}