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 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 | |||
34 | asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, | ||
35 | unsigned long error_code); | ||
31 | 36 | ||
32 | asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, | 37 | asmlinkage 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 | |||
604 | asmlinkage unsigned long sys_get_thread_area(void) | ||
605 | { | ||
606 | return current_thread_info()->tp_value; | ||
607 | } | ||
608 | |||
609 | asmlinkage 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). */ | ||
617 | asmlinkage int | ||
618 | sys_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 | |||
674 | asmlinkage int sys_atomic_barrier(void) | ||
675 | { | ||
676 | /* no code needed for uniprocs */ | ||
677 | return 0; | ||
678 | } | ||