Maxim Kuvyrkov wrote:
Here is the updated patch.
Hm, I've attached the patch without the unistd.h hunk. Here is the proper one.
-- Maxim K. CodeSourcery
From 828160ab5d329e15543a50d0b50ce50f2975966b Mon Sep 17 00:00:00 2001 From: Maxim Kuvyrkov <maxim@xxxxxxxxxxxxxxxx> Date: Tue, 25 Aug 2009 23:37:26 +0400 Subject: [PATCH] Add syscalls to support m68k NPTL. This patch adds several syscalls, private to M68K, that provide necessary functionality to support NPTL. The syscalls are read_tp, write_tp, atomic_cmpxchg_32 and atomic_barrier. The cmpxchg syscall is required for ColdFire as it doesn't support 'cas' instruction. Signed-off-by: Maxim Kuvyrkov <maxim@xxxxxxxxxxxxxxxx> --- arch/m68k/include/asm/thread_info_mm.h | 1 + arch/m68k/include/asm/unistd.h | 6 ++- arch/m68k/kernel/entry.S | 4 ++ arch/m68k/kernel/sys_m68k.c | 82 ++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 1 deletions(-) diff --git a/arch/m68k/include/asm/thread_info_mm.h b/arch/m68k/include/asm/thread_info_mm.h index af0fda4..a240244 100644 --- a/arch/m68k/include/asm/thread_info_mm.h +++ b/arch/m68k/include/asm/thread_info_mm.h @@ -10,6 +10,7 @@ struct thread_info { struct exec_domain *exec_domain; /* execution domain */ int preempt_count; /* 0 => preemptable, <0 => BUG */ __u32 cpu; /* should always be 0 on m68k */ + unsigned long tp_value; struct restart_block restart_block; }; diff --git a/arch/m68k/include/asm/unistd.h b/arch/m68k/include/asm/unistd.h index 946d869..c035c8b 100644 --- a/arch/m68k/include/asm/unistd.h +++ b/arch/m68k/include/asm/unistd.h @@ -336,10 +336,14 @@ #define __NR_pwritev 330 #define __NR_rt_tgsigqueueinfo 331 #define __NR_perf_counter_open 332 +#define __NR_read_tp 333 +#define __NR_write_tp 334 +#define __NR_atomic_cmpxchg_32 335 +#define __NR_atomic_barrier 336 #ifdef __KERNEL__ -#define NR_syscalls 333 +#define NR_syscalls 337 #define __ARCH_WANT_IPC_PARSE_VERSION #define __ARCH_WANT_OLD_READDIR diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index c3735cd..e2a245f 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -757,4 +757,8 @@ sys_call_table: .long sys_pwritev /* 330 */ .long sys_rt_tgsigqueueinfo .long sys_perf_counter_open + .long sys_read_tp + .long sys_write_tp + .long sys_atomic_cmpxchg_32 /* 335 */ + .long sys_atomic_barrier diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 7f54efa..03651e5 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -29,6 +29,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); /* common code for old and new mmaps */ static inline long do_mmap2( @@ -663,3 +668,80 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[]) : "d" (__a), "d" (__b), "d" (__c)); return __res; } + +asmlinkage unsigned long +sys_read_tp(void) +{ + return current_thread_info()->tp_value; +} + +asmlinkage int +sys_write_tp(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) +{ + struct mm_struct *mm = current->mm; + + /* This was borrowed from ARM's implementation. */ + for(;;) { + 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_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; +} -- 1.6.4