diff options
Diffstat (limited to 'arch/m68k/kernel/sys_m68k.c')
| -rw-r--r-- | arch/m68k/kernel/sys_m68k.c | 81 | 
1 files changed, 81 insertions, 0 deletions
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 218f441de66..e3ad2d67197 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -28,6 +28,11 @@  #include <asm/traps.h>  #include <asm/page.h>  #include <asm/unistd.h> +#include <linux/elf.h> +#include <asm/tlb.h> + +asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, +			     unsigned long error_code);  asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,  	unsigned long prot, unsigned long flags, @@ -595,3 +600,79 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[])  			: "d" (__a), "d" (__b), "d" (__c));  	return __res;  } + +asmlinkage unsigned long sys_get_thread_area(void) +{ +	return current_thread_info()->tp_value; +} + +asmlinkage int sys_set_thread_area(unsigned long tp) +{ +	current_thread_info()->tp_value = tp; +	return 0; +} + +/* This syscall gets its arguments in A0 (mem), D2 (oldval) and +   D1 (newval).  */ +asmlinkage int +sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5, +		      unsigned long __user * mem) +{ +	/* This was borrowed from ARM's implementation.  */ +	for (;;) { +		struct mm_struct *mm = current->mm; +		pgd_t *pgd; +		pmd_t *pmd; +		pte_t *pte; +		spinlock_t *ptl; +		unsigned long mem_value; + +		down_read(&mm->mmap_sem); +		pgd = pgd_offset(mm, (unsigned long)mem); +		if (!pgd_present(*pgd)) +			goto bad_access; +		pmd = pmd_offset(pgd, (unsigned long)mem); +		if (!pmd_present(*pmd)) +			goto bad_access; +		pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl); +		if (!pte_present(*pte) || !pte_dirty(*pte) +		    || !pte_write(*pte)) { +			pte_unmap_unlock(pte, ptl); +			goto bad_access; +		} + +		mem_value = *mem; +		if (mem_value == oldval) +			*mem = newval; + +		pte_unmap_unlock(pte, ptl); +		up_read(&mm->mmap_sem); +		return mem_value; + +	      bad_access: +		up_read(&mm->mmap_sem); +		/* This is not necessarily a bad access, we can get here if +		   a memory we're trying to write to should be copied-on-write. +		   Make the kernel do the necessary page stuff, then re-iterate. +		   Simulate a write access fault to do that.  */ +		{ +			/* The first argument of the function corresponds to +			   D1, which is the first field of struct pt_regs.  */ +			struct pt_regs *fp = (struct pt_regs *)&newval; + +			/* '3' is an RMW flag.  */ +			if (do_page_fault(fp, (unsigned long)mem, 3)) +				/* If the do_page_fault() failed, we don't +				   have anything meaningful to return. +				   There should be a SIGSEGV pending for +				   the process.  */ +				return 0xdeadbeef; +		} +	} +} + +asmlinkage int sys_atomic_barrier(void) +{ +	/* no code needed for uniprocs */ +	return 0; +}  |