| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * linux/arch/m32r/kernel/sys_m32r.c | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This file contains various random system calls that | 
					
						
							|  |  |  |  * have a non-standard calling sequence on the Linux/M32R platform. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Taken from i386 version. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <linux/errno.h>
 | 
					
						
							|  |  |  | #include <linux/sched.h>
 | 
					
						
							|  |  |  | #include <linux/mm.h>
 | 
					
						
							| 
									
										
										
										
											2007-07-30 22:00:47 +09:00
										 |  |  | #include <linux/fs.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | #include <linux/smp.h>
 | 
					
						
							|  |  |  | #include <linux/sem.h>
 | 
					
						
							|  |  |  | #include <linux/msg.h>
 | 
					
						
							|  |  |  | #include <linux/shm.h>
 | 
					
						
							|  |  |  | #include <linux/stat.h>
 | 
					
						
							|  |  |  | #include <linux/syscalls.h>
 | 
					
						
							|  |  |  | #include <linux/mman.h>
 | 
					
						
							|  |  |  | #include <linux/file.h>
 | 
					
						
							|  |  |  | #include <linux/utsname.h>
 | 
					
						
							| 
									
										
										
										
											2007-10-16 23:29:24 -07:00
										 |  |  | #include <linux/ipc.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include <asm/uaccess.h>
 | 
					
						
							|  |  |  | #include <asm/cachectl.h>
 | 
					
						
							|  |  |  | #include <asm/cacheflush.h>
 | 
					
						
							| 
									
										
										
										
											2006-10-02 02:18:34 -07:00
										 |  |  | #include <asm/syscall.h>
 | 
					
						
							|  |  |  | #include <asm/unistd.h>
 | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * sys_tas() - test-and-set | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2006-10-11 17:24:55 +01:00
										 |  |  | asmlinkage int sys_tas(int __user *addr) | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	int oldval; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!access_ok(VERIFY_WRITE, addr, sizeof (int))) | 
					
						
							|  |  |  | 		return -EFAULT; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
											  
											
												[PATCH] m32r: update sys_tas() routine
This patch updates and fixes sys_tas() routine for m32r.
In the previous implementation, a lockup rarely caused at sys_tas()
routine in SMP environment.
> > The problem is that touching *addr will generate an oops if that page isn't
> > paged in.  If we convert it to use get_user() then that's an improvement,
> > but we must not run get_user() under spinlock or local_irq_disable().
I rewrote sys_tas() routine by using "lock -> unlock" instructions, and
utilizing the m32r's interrupt handling characteristics; the m32r processor
can accept interrupts only at the 32-bit instruction boundary.  So, the
"unlock" instruction can be executed continuously after the "lock"
instruction execution without any interruptions.
In addition, to solve such a page_fault problem, I use a fixup code like
get_user().
And, as for the kernel lockup problem, we found that a calling
do_page_fault() routine with disabling interrupts might cause a lockup at
flush_tlb_others(), because we checked a completion of IPI handler's
operations in a spin-locked critical section.
Therefore, by using "lock -> unlock" code, we can implement the sys_tas()
rouitine without disabling interrupts explicitly, then no lockups would
happen at flush_tlb_others(), I hope.
Compile check and some working test in SMP environment have done.
Signed-off-by: Hirokazu Takata <takata@linux-m32r.org>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
											
										 
											2006-02-20 18:28:17 -08:00
										 |  |  | 	/* atomic operation:
 | 
					
						
							|  |  |  | 	 *   oldval = *addr; *addr = 1; | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	__asm__ __volatile__ ( | 
					
						
							|  |  |  | 		DCACHE_CLEAR("%0", "r4", "%1") | 
					
						
							|  |  |  | 		"	.fillinsn\n" | 
					
						
							|  |  |  | 		"1:\n" | 
					
						
							|  |  |  | 		"	lock	%0, @%1	    ->	unlock	%2, @%1\n" | 
					
						
							|  |  |  | 		"2:\n" | 
					
						
							|  |  |  | 		/* NOTE:
 | 
					
						
							|  |  |  | 		 *   The m32r processor can accept interrupts only | 
					
						
							|  |  |  | 		 *   at the 32-bit instruction boundary. | 
					
						
							|  |  |  | 		 *   So, in the above code, the "unlock" instruction | 
					
						
							|  |  |  | 		 *   can be executed continuously after the "lock" | 
					
						
							|  |  |  | 		 *   instruction execution without any interruptions. | 
					
						
							|  |  |  | 		 */ | 
					
						
							|  |  |  | 		".section .fixup,\"ax\"\n" | 
					
						
							|  |  |  | 		"	.balign 4\n" | 
					
						
							|  |  |  | 		"3:	ldi	%0, #%3\n" | 
					
						
							|  |  |  | 		"	seth	r14, #high(2b)\n" | 
					
						
							|  |  |  | 		"	or3	r14, r14, #low(2b)\n" | 
					
						
							|  |  |  | 		"	jmp	r14\n" | 
					
						
							|  |  |  | 		".previous\n" | 
					
						
							|  |  |  | 		".section __ex_table,\"a\"\n" | 
					
						
							|  |  |  | 		"	.balign 4\n" | 
					
						
							|  |  |  | 		"	.long 1b,3b\n" | 
					
						
							|  |  |  | 		".previous\n" | 
					
						
							|  |  |  | 		: "=&r" (oldval) | 
					
						
							|  |  |  | 		: "r" (addr), "r" (1), "i"(-EFAULT) | 
					
						
							|  |  |  | 		: "r14", "memory" | 
					
						
							|  |  |  | #ifdef CONFIG_CHIP_M32700_TS1
 | 
					
						
							|  |  |  | 		  , "r4" | 
					
						
							|  |  |  | #endif /* CONFIG_CHIP_M32700_TS1 */
 | 
					
						
							|  |  |  | 	); | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return oldval; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | asmlinkage int sys_cacheflush(void *addr, int bytes, int cache) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2007-10-20 01:14:39 +02:00
										 |  |  | 	/* This should flush more selectively ...  */ | 
					
						
							| 
									
										
										
										
											2005-04-16 15:20:36 -07:00
										 |  |  | 	_flush_cache_all(); | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | asmlinkage int sys_cachectl(char *addr, int nbytes, int op) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* Not implemented yet. */ | 
					
						
							|  |  |  | 	return -ENOSYS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2006-10-02 02:18:34 -07:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Do a system call from kernel instead of calling sys_execve so we | 
					
						
							|  |  |  |  * end up with proper pt_regs. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2010-08-17 23:52:56 +01:00
										 |  |  | int kernel_execve(const char *filename, | 
					
						
							|  |  |  | 		  const char *const argv[], | 
					
						
							|  |  |  | 		  const char *const envp[]) | 
					
						
							| 
									
										
										
										
											2006-10-02 02:18:34 -07:00
										 |  |  | { | 
					
						
							|  |  |  | 	register long __scno __asm__ ("r7") = __NR_execve; | 
					
						
							|  |  |  | 	register long __arg3 __asm__ ("r2") = (long)(envp); | 
					
						
							|  |  |  | 	register long __arg2 __asm__ ("r1") = (long)(argv); | 
					
						
							|  |  |  | 	register long __res __asm__ ("r0") = (long)(filename); | 
					
						
							|  |  |  | 	__asm__ __volatile__ ( | 
					
						
							|  |  |  | 		"trap #" SYSCALL_VECTOR "|| nop" | 
					
						
							|  |  |  | 		: "=r" (__res) | 
					
						
							|  |  |  | 		: "r" (__scno), "0" (__res), "r" (__arg2), | 
					
						
							|  |  |  | 			"r" (__arg3) | 
					
						
							|  |  |  | 		: "memory"); | 
					
						
							|  |  |  | 	return __res; | 
					
						
							|  |  |  | } |