aboutsummaryrefslogtreecommitdiffstats
path: root/arch/m68k/kernel/sys_m68k.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/m68k/kernel/sys_m68k.c')
-rw-r--r--arch/m68k/kernel/sys_m68k.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 218f441de667..e3ad2d671973 100644
--- a/arch/m68k/kernel/sys_m68k.c
+++ b/arch/m68k/kernel/sys_m68k.c
@@ -28,6 +28,11 @@
28#include <asm/traps.h> 28#include <asm/traps.h>
29#include <asm/page.h> 29#include <asm/page.h>
30#include <asm/unistd.h> 30#include <asm/unistd.h>
31#include <linux/elf.h>
32#include <asm/tlb.h>
33
34asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
35 unsigned long error_code);
31 36
32asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, 37asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
33 unsigned long prot, unsigned long flags, 38 unsigned long prot, unsigned long flags,
@@ -595,3 +600,79 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[])
595 : "d" (__a), "d" (__b), "d" (__c)); 600 : "d" (__a), "d" (__b), "d" (__c));
596 return __res; 601 return __res;
597} 602}
603
604asmlinkage unsigned long sys_get_thread_area(void)
605{
606 return current_thread_info()->tp_value;
607}
608
609asmlinkage int sys_set_thread_area(unsigned long tp)
610{
611 current_thread_info()->tp_value = tp;
612 return 0;
613}
614
615/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
616 D1 (newval). */
617asmlinkage int
618sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
619 unsigned long __user * mem)
620{
621 /* This was borrowed from ARM's implementation. */
622 for (;;) {
623 struct mm_struct *mm = current->mm;
624 pgd_t *pgd;
625 pmd_t *pmd;
626 pte_t *pte;
627 spinlock_t *ptl;
628 unsigned long mem_value;
629
630 down_read(&mm->mmap_sem);
631 pgd = pgd_offset(mm, (unsigned long)mem);
632 if (!pgd_present(*pgd))
633 goto bad_access;
634 pmd = pmd_offset(pgd, (unsigned long)mem);
635 if (!pmd_present(*pmd))
636 goto bad_access;
637 pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
638 if (!pte_present(*pte) || !pte_dirty(*pte)
639 || !pte_write(*pte)) {
640 pte_unmap_unlock(pte, ptl);
641 goto bad_access;
642 }
643
644 mem_value = *mem;
645 if (mem_value == oldval)
646 *mem = newval;
647
648 pte_unmap_unlock(pte, ptl);
649 up_read(&mm->mmap_sem);
650 return mem_value;
651
652 bad_access:
653 up_read(&mm->mmap_sem);
654 /* This is not necessarily a bad access, we can get here if
655 a memory we're trying to write to should be copied-on-write.
656 Make the kernel do the necessary page stuff, then re-iterate.
657 Simulate a write access fault to do that. */
658 {
659 /* The first argument of the function corresponds to
660 D1, which is the first field of struct pt_regs. */
661 struct pt_regs *fp = (struct pt_regs *)&newval;
662
663 /* '3' is an RMW flag. */
664 if (do_page_fault(fp, (unsigned long)mem, 3))
665 /* If the do_page_fault() failed, we don't
666 have anything meaningful to return.
667 There should be a SIGSEGV pending for
668 the process. */
669 return 0xdeadbeef;
670 }
671 }
672}
673
674asmlinkage int sys_atomic_barrier(void)
675{
676 /* no code needed for uniprocs */
677 return 0;
678}