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.c212
1 files changed, 81 insertions, 131 deletions
diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c
index 218f441de667..77896692eb0a 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,
@@ -41,137 +46,6 @@ asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
41 return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff); 46 return sys_mmap_pgoff(addr, len, prot, flags, fd, pgoff);
42} 47}
43 48
44/*
45 * Perform the select(nd, in, out, ex, tv) and mmap() system
46 * calls. Linux/m68k cloned Linux/i386, which didn't use to be able to
47 * handle more than 4 system call parameters, so these system calls
48 * used a memory block for parameter passing..
49 */
50
51struct mmap_arg_struct {
52 unsigned long addr;
53 unsigned long len;
54 unsigned long prot;
55 unsigned long flags;
56 unsigned long fd;
57 unsigned long offset;
58};
59
60asmlinkage int old_mmap(struct mmap_arg_struct __user *arg)
61{
62 struct mmap_arg_struct a;
63 int error = -EFAULT;
64
65 if (copy_from_user(&a, arg, sizeof(a)))
66 goto out;
67
68 error = -EINVAL;
69 if (a.offset & ~PAGE_MASK)
70 goto out;
71
72 error = sys_mmap_pgoff(a.addr, a.len, a.prot, a.flags, a.fd,
73 a.offset >> PAGE_SHIFT);
74out:
75 return error;
76}
77
78struct sel_arg_struct {
79 unsigned long n;
80 fd_set __user *inp, *outp, *exp;
81 struct timeval __user *tvp;
82};
83
84asmlinkage int old_select(struct sel_arg_struct __user *arg)
85{
86 struct sel_arg_struct a;
87
88 if (copy_from_user(&a, arg, sizeof(a)))
89 return -EFAULT;
90 /* sys_select() does the appropriate kernel locking */
91 return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp);
92}
93
94/*
95 * sys_ipc() is the de-multiplexer for the SysV IPC calls..
96 *
97 * This is really horribly ugly.
98 */
99asmlinkage int sys_ipc (uint call, int first, int second,
100 int third, void __user *ptr, long fifth)
101{
102 int version, ret;
103
104 version = call >> 16; /* hack for backward compatibility */
105 call &= 0xffff;
106
107 if (call <= SEMCTL)
108 switch (call) {
109 case SEMOP:
110 return sys_semop (first, ptr, second);
111 case SEMGET:
112 return sys_semget (first, second, third);
113 case SEMCTL: {
114 union semun fourth;
115 if (!ptr)
116 return -EINVAL;
117 if (get_user(fourth.__pad, (void __user *__user *) ptr))
118 return -EFAULT;
119 return sys_semctl (first, second, third, fourth);
120 }
121 default:
122 return -ENOSYS;
123 }
124 if (call <= MSGCTL)
125 switch (call) {
126 case MSGSND:
127 return sys_msgsnd (first, ptr, second, third);
128 case MSGRCV:
129 switch (version) {
130 case 0: {
131 struct ipc_kludge tmp;
132 if (!ptr)
133 return -EINVAL;
134 if (copy_from_user (&tmp, ptr, sizeof (tmp)))
135 return -EFAULT;
136 return sys_msgrcv (first, tmp.msgp, second,
137 tmp.msgtyp, third);
138 }
139 default:
140 return sys_msgrcv (first, ptr,
141 second, fifth, third);
142 }
143 case MSGGET:
144 return sys_msgget ((key_t) first, second);
145 case MSGCTL:
146 return sys_msgctl (first, second, ptr);
147 default:
148 return -ENOSYS;
149 }
150 if (call <= SHMCTL)
151 switch (call) {
152 case SHMAT:
153 switch (version) {
154 default: {
155 ulong raddr;
156 ret = do_shmat (first, ptr, second, &raddr);
157 if (ret)
158 return ret;
159 return put_user (raddr, (ulong __user *) third);
160 }
161 }
162 case SHMDT:
163 return sys_shmdt (ptr);
164 case SHMGET:
165 return sys_shmget (first, second, third);
166 case SHMCTL:
167 return sys_shmctl (first, second, ptr);
168 default:
169 return -ENOSYS;
170 }
171
172 return -EINVAL;
173}
174
175/* Convert virtual (user) address VADDR to physical address PADDR */ 49/* Convert virtual (user) address VADDR to physical address PADDR */
176#define virt_to_phys_040(vaddr) \ 50#define virt_to_phys_040(vaddr) \
177({ \ 51({ \
@@ -595,3 +469,79 @@ int kernel_execve(const char *filename, char *const argv[], char *const envp[])
595 : "d" (__a), "d" (__b), "d" (__c)); 469 : "d" (__a), "d" (__b), "d" (__c));
596 return __res; 470 return __res;
597} 471}
472
473asmlinkage unsigned long sys_get_thread_area(void)
474{
475 return current_thread_info()->tp_value;
476}
477
478asmlinkage int sys_set_thread_area(unsigned long tp)
479{
480 current_thread_info()->tp_value = tp;
481 return 0;
482}
483
484/* This syscall gets its arguments in A0 (mem), D2 (oldval) and
485 D1 (newval). */
486asmlinkage int
487sys_atomic_cmpxchg_32(unsigned long newval, int oldval, int d3, int d4, int d5,
488 unsigned long __user * mem)
489{
490 /* This was borrowed from ARM's implementation. */
491 for (;;) {
492 struct mm_struct *mm = current->mm;
493 pgd_t *pgd;
494 pmd_t *pmd;
495 pte_t *pte;
496 spinlock_t *ptl;
497 unsigned long mem_value;
498
499 down_read(&mm->mmap_sem);
500 pgd = pgd_offset(mm, (unsigned long)mem);
501 if (!pgd_present(*pgd))
502 goto bad_access;
503 pmd = pmd_offset(pgd, (unsigned long)mem);
504 if (!pmd_present(*pmd))
505 goto bad_access;
506 pte = pte_offset_map_lock(mm, pmd, (unsigned long)mem, &ptl);
507 if (!pte_present(*pte) || !pte_dirty(*pte)
508 || !pte_write(*pte)) {
509 pte_unmap_unlock(pte, ptl);
510 goto bad_access;
511 }
512
513 mem_value = *mem;
514 if (mem_value == oldval)
515 *mem = newval;
516
517 pte_unmap_unlock(pte, ptl);
518 up_read(&mm->mmap_sem);
519 return mem_value;
520
521 bad_access:
522 up_read(&mm->mmap_sem);
523 /* This is not necessarily a bad access, we can get here if
524 a memory we're trying to write to should be copied-on-write.
525 Make the kernel do the necessary page stuff, then re-iterate.
526 Simulate a write access fault to do that. */
527 {
528 /* The first argument of the function corresponds to
529 D1, which is the first field of struct pt_regs. */
530 struct pt_regs *fp = (struct pt_regs *)&newval;
531
532 /* '3' is an RMW flag. */
533 if (do_page_fault(fp, (unsigned long)mem, 3))
534 /* If the do_page_fault() failed, we don't
535 have anything meaningful to return.
536 There should be a SIGSEGV pending for
537 the process. */
538 return 0xdeadbeef;
539 }
540 }
541}
542
543asmlinkage int sys_atomic_barrier(void)
544{
545 /* no code needed for uniprocs */
546 return 0;
547}