 1400eb6567
			
		
	
	
	1400eb6567
	
	
	
		
			
			For non-SMP, uses the new random canary value that is stored in the
task struct whenever a new task is forked.  Based on ARM version in
df0698be14 and subject to the same
limitations: the variable GCC expects, __stack_chk_guard, is global,
so this will not work on SMP.
Quoting Nicolas Pitre <nico@fluxnic.net>: "One way to overcome this
GCC limitation would be to locate the __stack_chk_guard variable into
a memory page of its own for each CPU, and then use TLB locking to
have each CPU see its own page at the same virtual address for each of
them."
Signed-off-by: Gregory Fong <gregory.0xf0@gmail.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/5488/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
		
	
			
		
			
				
	
	
		
			251 lines
		
	
	
	
		
			5.1 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
			
		
		
	
	
			251 lines
		
	
	
	
		
			5.1 KiB
			
		
	
	
	
		
			ArmAsm
		
	
	
	
	
	
| /*
 | |
|  * This file is subject to the terms and conditions of the GNU General Public
 | |
|  * License.  See the file "COPYING" in the main directory of this archive
 | |
|  * for more details.
 | |
|  *
 | |
|  * Copyright (C) 1994, 1995, 1996, 1998, 1999, 2002, 2003 Ralf Baechle
 | |
|  * Copyright (C) 1996 David S. Miller (davem@davemloft.net)
 | |
|  * Copyright (C) 1994, 1995, 1996, by Andreas Busse
 | |
|  * Copyright (C) 1999 Silicon Graphics, Inc.
 | |
|  * Copyright (C) 2000 MIPS Technologies, Inc.
 | |
|  *    written by Carsten Langgaard, carstenl@mips.com
 | |
|  */
 | |
| #include <asm/asm.h>
 | |
| #include <asm/cachectl.h>
 | |
| #include <asm/fpregdef.h>
 | |
| #include <asm/mipsregs.h>
 | |
| #include <asm/asm-offsets.h>
 | |
| #include <asm/pgtable-bits.h>
 | |
| #include <asm/regdef.h>
 | |
| #include <asm/stackframe.h>
 | |
| #include <asm/thread_info.h>
 | |
| 
 | |
| #include <asm/asmmacro.h>
 | |
| 
 | |
| /*
 | |
|  * Offset to the current process status flags, the first 32 bytes of the
 | |
|  * stack are not used.
 | |
|  */
 | |
| #define ST_OFF (_THREAD_SIZE - 32 - PT_SIZE + PT_STATUS)
 | |
| 
 | |
| /*
 | |
|  * FPU context is saved iff the process has used it's FPU in the current
 | |
|  * time slice as indicated by _TIF_USEDFPU.  In any case, the CU1 bit for user
 | |
|  * space STATUS register should be 0, so that a process *always* starts its
 | |
|  * userland with FPU disabled after each context switch.
 | |
|  *
 | |
|  * FPU will be enabled as soon as the process accesses FPU again, through
 | |
|  * do_cpu() trap.
 | |
|  */
 | |
| 
 | |
| /*
 | |
|  * task_struct *resume(task_struct *prev, task_struct *next,
 | |
|  *		       struct thread_info *next_ti, int usedfpu)
 | |
|  */
 | |
| 	.align	5
 | |
| 	LEAF(resume)
 | |
| 	mfc0	t1, CP0_STATUS
 | |
| 	LONG_S	t1, THREAD_STATUS(a0)
 | |
| 	cpu_save_nonscratch a0
 | |
| 	LONG_S	ra, THREAD_REG31(a0)
 | |
| 
 | |
| 	/*
 | |
| 	 * check if we need to save FPU registers
 | |
| 	 */
 | |
| 
 | |
| 	beqz	a3, 1f
 | |
| 
 | |
| 	PTR_L	t3, TASK_THREAD_INFO(a0)
 | |
| 	/*
 | |
| 	 * clear saved user stack CU1 bit
 | |
| 	 */
 | |
| 	LONG_L	t0, ST_OFF(t3)
 | |
| 	li	t1, ~ST0_CU1
 | |
| 	and	t0, t0, t1
 | |
| 	LONG_S	t0, ST_OFF(t3)
 | |
| 
 | |
| 	fpu_save_double a0 t0 t1		# c0_status passed in t0
 | |
| 						# clobbers t1
 | |
| 1:
 | |
| 
 | |
| #if defined(CONFIG_CC_STACKPROTECTOR) && !defined(CONFIG_SMP)
 | |
| 	PTR_L	t8, __stack_chk_guard
 | |
| 	LONG_L	t9, TASK_STACK_CANARY(a1)
 | |
| 	LONG_S	t9, 0(t8)
 | |
| #endif
 | |
| 
 | |
| 	/*
 | |
| 	 * The order of restoring the registers takes care of the race
 | |
| 	 * updating $28, $29 and kernelsp without disabling ints.
 | |
| 	 */
 | |
| 	move	$28, a2
 | |
| 	cpu_restore_nonscratch a1
 | |
| 
 | |
| 	PTR_ADDU	t0, $28, _THREAD_SIZE - 32
 | |
| 	set_saved_sp	t0, t1, t2
 | |
| #ifdef CONFIG_MIPS_MT_SMTC
 | |
| 	/* Read-modify-writes of Status must be atomic on a VPE */
 | |
| 	mfc0	t2, CP0_TCSTATUS
 | |
| 	ori	t1, t2, TCSTATUS_IXMT
 | |
| 	mtc0	t1, CP0_TCSTATUS
 | |
| 	andi	t2, t2, TCSTATUS_IXMT
 | |
| 	_ehb
 | |
| 	DMT	8				# dmt	t0
 | |
| 	move	t1,ra
 | |
| 	jal	mips_ihb
 | |
| 	move	ra,t1
 | |
| #endif /* CONFIG_MIPS_MT_SMTC */
 | |
| 	mfc0	t1, CP0_STATUS		/* Do we really need this? */
 | |
| 	li	a3, 0xff01
 | |
| 	and	t1, a3
 | |
| 	LONG_L	a2, THREAD_STATUS(a1)
 | |
| 	nor	a3, $0, a3
 | |
| 	and	a2, a3
 | |
| 	or	a2, t1
 | |
| 	mtc0	a2, CP0_STATUS
 | |
| #ifdef CONFIG_MIPS_MT_SMTC
 | |
| 	_ehb
 | |
| 	andi	t0, t0, VPECONTROL_TE
 | |
| 	beqz	t0, 1f
 | |
| 	emt
 | |
| 1:
 | |
| 	mfc0	t1, CP0_TCSTATUS
 | |
| 	xori	t1, t1, TCSTATUS_IXMT
 | |
| 	or	t1, t1, t2
 | |
| 	mtc0	t1, CP0_TCSTATUS
 | |
| 	_ehb
 | |
| #endif /* CONFIG_MIPS_MT_SMTC */
 | |
| 	move	v0, a0
 | |
| 	jr	ra
 | |
| 	END(resume)
 | |
| 
 | |
| /*
 | |
|  * Save a thread's fp context.
 | |
|  */
 | |
| LEAF(_save_fp)
 | |
| #ifdef CONFIG_64BIT
 | |
| 	mfc0	t0, CP0_STATUS
 | |
| #endif
 | |
| 	fpu_save_double a0 t0 t1		# clobbers t1
 | |
| 	jr	ra
 | |
| 	END(_save_fp)
 | |
| 
 | |
| /*
 | |
|  * Restore a thread's fp context.
 | |
|  */
 | |
| LEAF(_restore_fp)
 | |
| #ifdef CONFIG_64BIT
 | |
| 	mfc0	t0, CP0_STATUS
 | |
| #endif
 | |
| 	fpu_restore_double a0 t0 t1		# clobbers t1
 | |
| 	jr	ra
 | |
| 	END(_restore_fp)
 | |
| 
 | |
| /*
 | |
|  * Load the FPU with signalling NANS.  This bit pattern we're using has
 | |
|  * the property that no matter whether considered as single or as double
 | |
|  * precision represents signaling NANS.
 | |
|  *
 | |
|  * We initialize fcr31 to rounding to nearest, no exceptions.
 | |
|  */
 | |
| 
 | |
| #define FPU_DEFAULT  0x00000000
 | |
| 
 | |
| LEAF(_init_fpu)
 | |
| #ifdef CONFIG_MIPS_MT_SMTC
 | |
| 	/* Rather than manipulate per-VPE Status, set per-TC bit in TCStatus */
 | |
| 	mfc0	t0, CP0_TCSTATUS
 | |
| 	/* Bit position is the same for Status, TCStatus */
 | |
| 	li	t1, ST0_CU1
 | |
| 	or	t0, t1
 | |
| 	mtc0	t0, CP0_TCSTATUS
 | |
| #else /* Normal MIPS CU1 enable */
 | |
| 	mfc0	t0, CP0_STATUS
 | |
| 	li	t1, ST0_CU1
 | |
| 	or	t0, t1
 | |
| 	mtc0	t0, CP0_STATUS
 | |
| #endif /* CONFIG_MIPS_MT_SMTC */
 | |
| 	enable_fpu_hazard
 | |
| 
 | |
| 	li	t1, FPU_DEFAULT
 | |
| 	ctc1	t1, fcr31
 | |
| 
 | |
| 	li	t1, -1				# SNaN
 | |
| 
 | |
| #ifdef CONFIG_64BIT
 | |
| 	sll	t0, t0, 5
 | |
| 	bgez	t0, 1f				# 16 / 32 register mode?
 | |
| 
 | |
| 	dmtc1	t1, $f1
 | |
| 	dmtc1	t1, $f3
 | |
| 	dmtc1	t1, $f5
 | |
| 	dmtc1	t1, $f7
 | |
| 	dmtc1	t1, $f9
 | |
| 	dmtc1	t1, $f11
 | |
| 	dmtc1	t1, $f13
 | |
| 	dmtc1	t1, $f15
 | |
| 	dmtc1	t1, $f17
 | |
| 	dmtc1	t1, $f19
 | |
| 	dmtc1	t1, $f21
 | |
| 	dmtc1	t1, $f23
 | |
| 	dmtc1	t1, $f25
 | |
| 	dmtc1	t1, $f27
 | |
| 	dmtc1	t1, $f29
 | |
| 	dmtc1	t1, $f31
 | |
| 1:
 | |
| #endif
 | |
| 
 | |
| #ifdef CONFIG_CPU_MIPS32
 | |
| 	mtc1	t1, $f0
 | |
| 	mtc1	t1, $f1
 | |
| 	mtc1	t1, $f2
 | |
| 	mtc1	t1, $f3
 | |
| 	mtc1	t1, $f4
 | |
| 	mtc1	t1, $f5
 | |
| 	mtc1	t1, $f6
 | |
| 	mtc1	t1, $f7
 | |
| 	mtc1	t1, $f8
 | |
| 	mtc1	t1, $f9
 | |
| 	mtc1	t1, $f10
 | |
| 	mtc1	t1, $f11
 | |
| 	mtc1	t1, $f12
 | |
| 	mtc1	t1, $f13
 | |
| 	mtc1	t1, $f14
 | |
| 	mtc1	t1, $f15
 | |
| 	mtc1	t1, $f16
 | |
| 	mtc1	t1, $f17
 | |
| 	mtc1	t1, $f18
 | |
| 	mtc1	t1, $f19
 | |
| 	mtc1	t1, $f20
 | |
| 	mtc1	t1, $f21
 | |
| 	mtc1	t1, $f22
 | |
| 	mtc1	t1, $f23
 | |
| 	mtc1	t1, $f24
 | |
| 	mtc1	t1, $f25
 | |
| 	mtc1	t1, $f26
 | |
| 	mtc1	t1, $f27
 | |
| 	mtc1	t1, $f28
 | |
| 	mtc1	t1, $f29
 | |
| 	mtc1	t1, $f30
 | |
| 	mtc1	t1, $f31
 | |
| #else
 | |
| 	.set	mips3
 | |
| 	dmtc1	t1, $f0
 | |
| 	dmtc1	t1, $f2
 | |
| 	dmtc1	t1, $f4
 | |
| 	dmtc1	t1, $f6
 | |
| 	dmtc1	t1, $f8
 | |
| 	dmtc1	t1, $f10
 | |
| 	dmtc1	t1, $f12
 | |
| 	dmtc1	t1, $f14
 | |
| 	dmtc1	t1, $f16
 | |
| 	dmtc1	t1, $f18
 | |
| 	dmtc1	t1, $f20
 | |
| 	dmtc1	t1, $f22
 | |
| 	dmtc1	t1, $f24
 | |
| 	dmtc1	t1, $f26
 | |
| 	dmtc1	t1, $f28
 | |
| 	dmtc1	t1, $f30
 | |
| #endif
 | |
| 	jr	ra
 | |
| 	END(_init_fpu)
 |