diff options
Diffstat (limited to 'arch/m68k/kernel/sys_m68k.c')
-rw-r--r-- | arch/m68k/kernel/sys_m68k.c | 212 |
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 | |||
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, |
@@ -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 | |||
51 | struct 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 | |||
60 | asmlinkage 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); | ||
74 | out: | ||
75 | return error; | ||
76 | } | ||
77 | |||
78 | struct sel_arg_struct { | ||
79 | unsigned long n; | ||
80 | fd_set __user *inp, *outp, *exp; | ||
81 | struct timeval __user *tvp; | ||
82 | }; | ||
83 | |||
84 | asmlinkage 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 | */ | ||
99 | asmlinkage 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 | |||
473 | asmlinkage unsigned long sys_get_thread_area(void) | ||
474 | { | ||
475 | return current_thread_info()->tp_value; | ||
476 | } | ||
477 | |||
478 | asmlinkage 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). */ | ||
486 | asmlinkage int | ||
487 | sys_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 | |||
543 | asmlinkage int sys_atomic_barrier(void) | ||
544 | { | ||
545 | /* no code needed for uniprocs */ | ||
546 | return 0; | ||
547 | } | ||