Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * sys_ppc32.c: Conversion between 32bit and 64bit native syscalls. | |
3 | * | |
4 | * Copyright (C) 2001 IBM | |
5 | * Copyright (C) 1997,1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz) | |
6 | * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) | |
7 | * | |
8 | * These routines maintain argument size conversion between 32bit and 64bit | |
9 | * environment. | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public License | |
13 | * as published by the Free Software Foundation; either version | |
14 | * 2 of the License, or (at your option) any later version. | |
15 | */ | |
16 | ||
1da177e4 LT |
17 | #include <linux/kernel.h> |
18 | #include <linux/sched.h> | |
19 | #include <linux/fs.h> | |
20 | #include <linux/mm.h> | |
21 | #include <linux/file.h> | |
22 | #include <linux/signal.h> | |
23 | #include <linux/resource.h> | |
24 | #include <linux/times.h> | |
25 | #include <linux/utsname.h> | |
1da177e4 LT |
26 | #include <linux/smp.h> |
27 | #include <linux/smp_lock.h> | |
28 | #include <linux/sem.h> | |
29 | #include <linux/msg.h> | |
30 | #include <linux/shm.h> | |
1da177e4 LT |
31 | #include <linux/poll.h> |
32 | #include <linux/personality.h> | |
33 | #include <linux/stat.h> | |
1da177e4 | 34 | #include <linux/mman.h> |
1da177e4 | 35 | #include <linux/in.h> |
1da177e4 LT |
36 | #include <linux/syscalls.h> |
37 | #include <linux/unistd.h> | |
38 | #include <linux/sysctl.h> | |
39 | #include <linux/binfmts.h> | |
1da177e4 LT |
40 | #include <linux/security.h> |
41 | #include <linux/compat.h> | |
42 | #include <linux/ptrace.h> | |
1da177e4 | 43 | #include <linux/elf.h> |
cba4fbbf | 44 | #include <linux/ipc.h> |
1da177e4 | 45 | |
1da177e4 LT |
46 | #include <asm/ptrace.h> |
47 | #include <asm/types.h> | |
1da177e4 LT |
48 | #include <asm/uaccess.h> |
49 | #include <asm/unistd.h> | |
50 | #include <asm/semaphore.h> | |
1da177e4 LT |
51 | #include <asm/time.h> |
52 | #include <asm/mmu_context.h> | |
d387899f | 53 | #include <asm/ppc-pci.h> |
369cf4b9 | 54 | #include <asm/syscalls.h> |
1da177e4 | 55 | |
1da177e4 LT |
56 | struct old_linux_dirent32 { |
57 | u32 d_ino; | |
58 | u32 d_offset; | |
59 | unsigned short d_namlen; | |
60 | char d_name[1]; | |
61 | }; | |
62 | ||
63 | struct readdir_callback32 { | |
64 | struct old_linux_dirent32 __user * dirent; | |
65 | int count; | |
66 | }; | |
67 | ||
68 | static int fillonedir(void * __buf, const char * name, int namlen, | |
afefdbb2 | 69 | off_t offset, u64 ino, unsigned int d_type) |
1da177e4 LT |
70 | { |
71 | struct readdir_callback32 * buf = (struct readdir_callback32 *) __buf; | |
72 | struct old_linux_dirent32 __user * dirent; | |
afefdbb2 | 73 | ino_t d_ino; |
1da177e4 LT |
74 | |
75 | if (buf->count) | |
76 | return -EINVAL; | |
afefdbb2 DH |
77 | d_ino = ino; |
78 | if (sizeof(d_ino) < sizeof(ino) && d_ino != ino) | |
79 | return -EOVERFLOW; | |
1da177e4 LT |
80 | buf->count++; |
81 | dirent = buf->dirent; | |
afefdbb2 | 82 | put_user(d_ino, &dirent->d_ino); |
1da177e4 LT |
83 | put_user(offset, &dirent->d_offset); |
84 | put_user(namlen, &dirent->d_namlen); | |
85 | copy_to_user(dirent->d_name, name, namlen); | |
86 | put_user(0, dirent->d_name + namlen); | |
87 | return 0; | |
88 | } | |
89 | ||
90 | asmlinkage int old32_readdir(unsigned int fd, struct old_linux_dirent32 __user *dirent, unsigned int count) | |
91 | { | |
92 | int error = -EBADF; | |
93 | struct file * file; | |
94 | struct readdir_callback32 buf; | |
95 | ||
96 | file = fget(fd); | |
97 | if (!file) | |
98 | goto out; | |
99 | ||
100 | buf.count = 0; | |
101 | buf.dirent = dirent; | |
102 | ||
103 | error = vfs_readdir(file, (filldir_t)fillonedir, &buf); | |
104 | if (error < 0) | |
105 | goto out_putf; | |
106 | error = buf.count; | |
107 | ||
108 | out_putf: | |
109 | fput(file); | |
110 | out: | |
111 | return error; | |
112 | } | |
113 | ||
1da177e4 LT |
114 | asmlinkage long ppc32_select(u32 n, compat_ulong_t __user *inp, |
115 | compat_ulong_t __user *outp, compat_ulong_t __user *exp, | |
116 | compat_uptr_t tvp_x) | |
117 | { | |
118 | /* sign extend n */ | |
119 | return compat_sys_select((int)n, inp, outp, exp, compat_ptr(tvp_x)); | |
120 | } | |
121 | ||
122 | int cp_compat_stat(struct kstat *stat, struct compat_stat __user *statbuf) | |
123 | { | |
afefdbb2 | 124 | compat_ino_t ino; |
1da177e4 LT |
125 | long err; |
126 | ||
127 | if (stat->size > MAX_NON_LFS || !new_valid_dev(stat->dev) || | |
128 | !new_valid_dev(stat->rdev)) | |
129 | return -EOVERFLOW; | |
130 | ||
afefdbb2 DH |
131 | ino = stat->ino; |
132 | if (sizeof(ino) < sizeof(stat->ino) && ino != stat->ino) | |
133 | return -EOVERFLOW; | |
134 | ||
1da177e4 LT |
135 | err = access_ok(VERIFY_WRITE, statbuf, sizeof(*statbuf)) ? 0 : -EFAULT; |
136 | err |= __put_user(new_encode_dev(stat->dev), &statbuf->st_dev); | |
afefdbb2 | 137 | err |= __put_user(ino, &statbuf->st_ino); |
1da177e4 LT |
138 | err |= __put_user(stat->mode, &statbuf->st_mode); |
139 | err |= __put_user(stat->nlink, &statbuf->st_nlink); | |
140 | err |= __put_user(stat->uid, &statbuf->st_uid); | |
141 | err |= __put_user(stat->gid, &statbuf->st_gid); | |
142 | err |= __put_user(new_encode_dev(stat->rdev), &statbuf->st_rdev); | |
143 | err |= __put_user(stat->size, &statbuf->st_size); | |
144 | err |= __put_user(stat->atime.tv_sec, &statbuf->st_atime); | |
145 | err |= __put_user(stat->atime.tv_nsec, &statbuf->st_atime_nsec); | |
146 | err |= __put_user(stat->mtime.tv_sec, &statbuf->st_mtime); | |
147 | err |= __put_user(stat->mtime.tv_nsec, &statbuf->st_mtime_nsec); | |
148 | err |= __put_user(stat->ctime.tv_sec, &statbuf->st_ctime); | |
149 | err |= __put_user(stat->ctime.tv_nsec, &statbuf->st_ctime_nsec); | |
150 | err |= __put_user(stat->blksize, &statbuf->st_blksize); | |
151 | err |= __put_user(stat->blocks, &statbuf->st_blocks); | |
152 | err |= __put_user(0, &statbuf->__unused4[0]); | |
153 | err |= __put_user(0, &statbuf->__unused4[1]); | |
154 | ||
155 | return err; | |
156 | } | |
157 | ||
158 | /* Note: it is necessary to treat option as an unsigned int, | |
159 | * with the corresponding cast to a signed int to insure that the | |
160 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
161 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
162 | */ | |
b09a4913 | 163 | asmlinkage long compat_sys_sysfs(u32 option, u32 arg1, u32 arg2) |
1da177e4 LT |
164 | { |
165 | return sys_sysfs((int)option, arg1, arg2); | |
166 | } | |
167 | ||
b09a4913 | 168 | asmlinkage long compat_sys_pause(void) |
1da177e4 LT |
169 | { |
170 | current->state = TASK_INTERRUPTIBLE; | |
171 | schedule(); | |
172 | ||
173 | return -ERESTARTNOHAND; | |
174 | } | |
175 | ||
1da177e4 LT |
176 | static inline long get_ts32(struct timespec *o, struct compat_timeval __user *i) |
177 | { | |
178 | long usec; | |
179 | ||
180 | if (!access_ok(VERIFY_READ, i, sizeof(*i))) | |
181 | return -EFAULT; | |
182 | if (__get_user(o->tv_sec, &i->tv_sec)) | |
183 | return -EFAULT; | |
184 | if (__get_user(usec, &i->tv_usec)) | |
185 | return -EFAULT; | |
186 | o->tv_nsec = usec * 1000; | |
187 | return 0; | |
188 | } | |
189 | ||
190 | static inline long put_tv32(struct compat_timeval __user *o, struct timeval *i) | |
191 | { | |
192 | return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || | |
193 | (__put_user(i->tv_sec, &o->tv_sec) | | |
194 | __put_user(i->tv_usec, &o->tv_usec))); | |
195 | } | |
196 | ||
1da177e4 LT |
197 | |
198 | ||
199 | ||
200 | /* Translations due to time_t size differences. Which affects all | |
201 | sorts of things, like timeval and itimerval. */ | |
202 | extern struct timezone sys_tz; | |
203 | ||
b09a4913 | 204 | asmlinkage long compat_sys_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) |
1da177e4 LT |
205 | { |
206 | if (tv) { | |
207 | struct timeval ktv; | |
208 | do_gettimeofday(&ktv); | |
209 | if (put_tv32(tv, &ktv)) | |
210 | return -EFAULT; | |
211 | } | |
212 | if (tz) { | |
213 | if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) | |
214 | return -EFAULT; | |
215 | } | |
216 | ||
217 | return 0; | |
218 | } | |
219 | ||
220 | ||
221 | ||
b09a4913 | 222 | asmlinkage long compat_sys_settimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) |
1da177e4 LT |
223 | { |
224 | struct timespec kts; | |
225 | struct timezone ktz; | |
226 | ||
227 | if (tv) { | |
228 | if (get_ts32(&kts, tv)) | |
229 | return -EFAULT; | |
230 | } | |
231 | if (tz) { | |
232 | if (copy_from_user(&ktz, tz, sizeof(ktz))) | |
233 | return -EFAULT; | |
234 | } | |
235 | ||
236 | return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); | |
237 | } | |
238 | ||
239 | #ifdef CONFIG_SYSVIPC | |
b09a4913 | 240 | long compat_sys_ipc(u32 call, u32 first, u32 second, u32 third, compat_uptr_t ptr, |
1da177e4 LT |
241 | u32 fifth) |
242 | { | |
243 | int version; | |
244 | ||
245 | version = call >> 16; /* hack for backward compatibility */ | |
246 | call &= 0xffff; | |
247 | ||
248 | switch (call) { | |
249 | ||
250 | case SEMTIMEDOP: | |
251 | if (fifth) | |
252 | /* sign extend semid */ | |
253 | return compat_sys_semtimedop((int)first, | |
254 | compat_ptr(ptr), second, | |
255 | compat_ptr(fifth)); | |
256 | /* else fall through for normal semop() */ | |
257 | case SEMOP: | |
258 | /* struct sembuf is the same on 32 and 64bit :)) */ | |
259 | /* sign extend semid */ | |
260 | return sys_semtimedop((int)first, compat_ptr(ptr), second, | |
261 | NULL); | |
262 | case SEMGET: | |
263 | /* sign extend key, nsems */ | |
264 | return sys_semget((int)first, (int)second, third); | |
265 | case SEMCTL: | |
266 | /* sign extend semid, semnum */ | |
267 | return compat_sys_semctl((int)first, (int)second, third, | |
268 | compat_ptr(ptr)); | |
269 | ||
270 | case MSGSND: | |
271 | /* sign extend msqid */ | |
272 | return compat_sys_msgsnd((int)first, (int)second, third, | |
273 | compat_ptr(ptr)); | |
274 | case MSGRCV: | |
275 | /* sign extend msqid, msgtyp */ | |
276 | return compat_sys_msgrcv((int)first, second, (int)fifth, | |
277 | third, version, compat_ptr(ptr)); | |
278 | case MSGGET: | |
279 | /* sign extend key */ | |
280 | return sys_msgget((int)first, second); | |
281 | case MSGCTL: | |
282 | /* sign extend msqid */ | |
283 | return compat_sys_msgctl((int)first, second, compat_ptr(ptr)); | |
284 | ||
285 | case SHMAT: | |
286 | /* sign extend shmid */ | |
287 | return compat_sys_shmat((int)first, second, third, version, | |
288 | compat_ptr(ptr)); | |
289 | case SHMDT: | |
290 | return sys_shmdt(compat_ptr(ptr)); | |
291 | case SHMGET: | |
292 | /* sign extend key_t */ | |
293 | return sys_shmget((int)first, second, third); | |
294 | case SHMCTL: | |
295 | /* sign extend shmid */ | |
296 | return compat_sys_shmctl((int)first, second, compat_ptr(ptr)); | |
297 | ||
298 | default: | |
299 | return -ENOSYS; | |
300 | } | |
301 | ||
302 | return -ENOSYS; | |
303 | } | |
304 | #endif | |
305 | ||
306 | /* Note: it is necessary to treat out_fd and in_fd as unsigned ints, | |
307 | * with the corresponding cast to a signed int to insure that the | |
308 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
309 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
310 | */ | |
b09a4913 | 311 | asmlinkage long compat_sys_sendfile(u32 out_fd, u32 in_fd, compat_off_t __user * offset, u32 count) |
1da177e4 LT |
312 | { |
313 | mm_segment_t old_fs = get_fs(); | |
314 | int ret; | |
315 | off_t of; | |
316 | off_t __user *up; | |
317 | ||
318 | if (offset && get_user(of, offset)) | |
319 | return -EFAULT; | |
320 | ||
321 | /* The __user pointer cast is valid because of the set_fs() */ | |
322 | set_fs(KERNEL_DS); | |
323 | up = offset ? (off_t __user *) &of : NULL; | |
324 | ret = sys_sendfile((int)out_fd, (int)in_fd, up, count); | |
325 | set_fs(old_fs); | |
326 | ||
327 | if (offset && put_user(of, offset)) | |
328 | return -EFAULT; | |
329 | ||
330 | return ret; | |
331 | } | |
332 | ||
b09a4913 | 333 | asmlinkage int compat_sys_sendfile64(int out_fd, int in_fd, compat_loff_t __user *offset, s32 count) |
1da177e4 LT |
334 | { |
335 | mm_segment_t old_fs = get_fs(); | |
336 | int ret; | |
337 | loff_t lof; | |
338 | loff_t __user *up; | |
339 | ||
340 | if (offset && get_user(lof, offset)) | |
341 | return -EFAULT; | |
342 | ||
343 | /* The __user pointer cast is valid because of the set_fs() */ | |
344 | set_fs(KERNEL_DS); | |
345 | up = offset ? (loff_t __user *) &lof : NULL; | |
346 | ret = sys_sendfile64(out_fd, in_fd, up, count); | |
347 | set_fs(old_fs); | |
348 | ||
349 | if (offset && put_user(lof, offset)) | |
350 | return -EFAULT; | |
351 | ||
352 | return ret; | |
353 | } | |
354 | ||
b09a4913 | 355 | long compat_sys_execve(unsigned long a0, unsigned long a1, unsigned long a2, |
1da177e4 LT |
356 | unsigned long a3, unsigned long a4, unsigned long a5, |
357 | struct pt_regs *regs) | |
358 | { | |
359 | int error; | |
360 | char * filename; | |
361 | ||
362 | filename = getname((char __user *) a0); | |
363 | error = PTR_ERR(filename); | |
364 | if (IS_ERR(filename)) | |
365 | goto out; | |
366 | flush_fp_to_thread(current); | |
367 | flush_altivec_to_thread(current); | |
368 | ||
369 | error = compat_do_execve(filename, compat_ptr(a1), compat_ptr(a2), regs); | |
370 | ||
371 | if (error == 0) { | |
372 | task_lock(current); | |
373 | current->ptrace &= ~PT_DTRACE; | |
374 | task_unlock(current); | |
375 | } | |
376 | putname(filename); | |
377 | ||
378 | out: | |
379 | return error; | |
380 | } | |
381 | ||
1da177e4 LT |
382 | /* Note: it is necessary to treat option as an unsigned int, |
383 | * with the corresponding cast to a signed int to insure that the | |
384 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
385 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
386 | */ | |
b09a4913 | 387 | asmlinkage long compat_sys_prctl(u32 option, u32 arg2, u32 arg3, u32 arg4, u32 arg5) |
1da177e4 LT |
388 | { |
389 | return sys_prctl((int)option, | |
390 | (unsigned long) arg2, | |
391 | (unsigned long) arg3, | |
392 | (unsigned long) arg4, | |
393 | (unsigned long) arg5); | |
394 | } | |
395 | ||
396 | /* Note: it is necessary to treat pid as an unsigned int, | |
397 | * with the corresponding cast to a signed int to insure that the | |
398 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
399 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
400 | */ | |
b09a4913 | 401 | asmlinkage long compat_sys_sched_rr_get_interval(u32 pid, struct compat_timespec __user *interval) |
1da177e4 LT |
402 | { |
403 | struct timespec t; | |
404 | int ret; | |
405 | mm_segment_t old_fs = get_fs (); | |
406 | ||
407 | /* The __user pointer cast is valid because of the set_fs() */ | |
408 | set_fs (KERNEL_DS); | |
409 | ret = sys_sched_rr_get_interval((int)pid, (struct timespec __user *) &t); | |
410 | set_fs (old_fs); | |
411 | if (put_compat_timespec(&t, interval)) | |
412 | return -EFAULT; | |
413 | return ret; | |
414 | } | |
415 | ||
1da177e4 LT |
416 | /* Note: it is necessary to treat mode as an unsigned int, |
417 | * with the corresponding cast to a signed int to insure that the | |
418 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
419 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
420 | */ | |
b09a4913 | 421 | asmlinkage long compat_sys_access(const char __user * filename, u32 mode) |
1da177e4 LT |
422 | { |
423 | return sys_access(filename, (int)mode); | |
424 | } | |
425 | ||
426 | ||
427 | /* Note: it is necessary to treat mode as an unsigned int, | |
428 | * with the corresponding cast to a signed int to insure that the | |
429 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
430 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
431 | */ | |
b09a4913 | 432 | asmlinkage long compat_sys_creat(const char __user * pathname, u32 mode) |
1da177e4 LT |
433 | { |
434 | return sys_creat(pathname, (int)mode); | |
435 | } | |
436 | ||
437 | ||
438 | /* Note: it is necessary to treat pid and options as unsigned ints, | |
439 | * with the corresponding cast to a signed int to insure that the | |
440 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
441 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
442 | */ | |
b09a4913 | 443 | asmlinkage long compat_sys_waitpid(u32 pid, unsigned int __user * stat_addr, u32 options) |
1da177e4 LT |
444 | { |
445 | return sys_waitpid((int)pid, stat_addr, (int)options); | |
446 | } | |
447 | ||
448 | ||
449 | /* Note: it is necessary to treat gidsetsize as an unsigned int, | |
450 | * with the corresponding cast to a signed int to insure that the | |
451 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
452 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
453 | */ | |
b09a4913 | 454 | asmlinkage long compat_sys_getgroups(u32 gidsetsize, gid_t __user *grouplist) |
1da177e4 LT |
455 | { |
456 | return sys_getgroups((int)gidsetsize, grouplist); | |
457 | } | |
458 | ||
459 | ||
460 | /* Note: it is necessary to treat pid as an unsigned int, | |
461 | * with the corresponding cast to a signed int to insure that the | |
462 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
463 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
464 | */ | |
b09a4913 | 465 | asmlinkage long compat_sys_getpgid(u32 pid) |
1da177e4 LT |
466 | { |
467 | return sys_getpgid((int)pid); | |
468 | } | |
469 | ||
470 | ||
1da177e4 LT |
471 | |
472 | /* Note: it is necessary to treat pid as an unsigned int, | |
473 | * with the corresponding cast to a signed int to insure that the | |
474 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
475 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
476 | */ | |
b09a4913 | 477 | asmlinkage long compat_sys_getsid(u32 pid) |
1da177e4 LT |
478 | { |
479 | return sys_getsid((int)pid); | |
480 | } | |
481 | ||
482 | ||
483 | /* Note: it is necessary to treat pid and sig as unsigned ints, | |
484 | * with the corresponding cast to a signed int to insure that the | |
485 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
486 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
487 | */ | |
b09a4913 | 488 | asmlinkage long compat_sys_kill(u32 pid, u32 sig) |
1da177e4 LT |
489 | { |
490 | return sys_kill((int)pid, (int)sig); | |
491 | } | |
492 | ||
493 | ||
494 | /* Note: it is necessary to treat mode as an unsigned int, | |
495 | * with the corresponding cast to a signed int to insure that the | |
496 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
497 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
498 | */ | |
b09a4913 | 499 | asmlinkage long compat_sys_mkdir(const char __user * pathname, u32 mode) |
1da177e4 LT |
500 | { |
501 | return sys_mkdir(pathname, (int)mode); | |
502 | } | |
503 | ||
b09a4913 | 504 | long compat_sys_nice(u32 increment) |
1da177e4 LT |
505 | { |
506 | /* sign extend increment */ | |
507 | return sys_nice((int)increment); | |
508 | } | |
509 | ||
510 | off_t ppc32_lseek(unsigned int fd, u32 offset, unsigned int origin) | |
511 | { | |
512 | /* sign extend n */ | |
513 | return sys_lseek(fd, (int)offset, origin); | |
514 | } | |
515 | ||
1da177e4 LT |
516 | /* Note: it is necessary to treat bufsiz as an unsigned int, |
517 | * with the corresponding cast to a signed int to insure that the | |
518 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
519 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
520 | */ | |
b09a4913 | 521 | asmlinkage long compat_sys_readlink(const char __user * path, char __user * buf, u32 bufsiz) |
1da177e4 LT |
522 | { |
523 | return sys_readlink(path, buf, (int)bufsiz); | |
524 | } | |
525 | ||
526 | /* Note: it is necessary to treat option as an unsigned int, | |
527 | * with the corresponding cast to a signed int to insure that the | |
528 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
529 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
530 | */ | |
b09a4913 | 531 | asmlinkage long compat_sys_sched_get_priority_max(u32 policy) |
1da177e4 LT |
532 | { |
533 | return sys_sched_get_priority_max((int)policy); | |
534 | } | |
535 | ||
536 | ||
537 | /* Note: it is necessary to treat policy as an unsigned int, | |
538 | * with the corresponding cast to a signed int to insure that the | |
539 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
540 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
541 | */ | |
b09a4913 | 542 | asmlinkage long compat_sys_sched_get_priority_min(u32 policy) |
1da177e4 LT |
543 | { |
544 | return sys_sched_get_priority_min((int)policy); | |
545 | } | |
546 | ||
547 | ||
548 | /* Note: it is necessary to treat pid as an unsigned int, | |
549 | * with the corresponding cast to a signed int to insure that the | |
550 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
551 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
552 | */ | |
b09a4913 | 553 | asmlinkage long compat_sys_sched_getparam(u32 pid, struct sched_param __user *param) |
1da177e4 LT |
554 | { |
555 | return sys_sched_getparam((int)pid, param); | |
556 | } | |
557 | ||
558 | ||
559 | /* Note: it is necessary to treat pid as an unsigned int, | |
560 | * with the corresponding cast to a signed int to insure that the | |
561 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
562 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
563 | */ | |
b09a4913 | 564 | asmlinkage long compat_sys_sched_getscheduler(u32 pid) |
1da177e4 LT |
565 | { |
566 | return sys_sched_getscheduler((int)pid); | |
567 | } | |
568 | ||
569 | ||
570 | /* Note: it is necessary to treat pid as an unsigned int, | |
571 | * with the corresponding cast to a signed int to insure that the | |
572 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
573 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
574 | */ | |
b09a4913 | 575 | asmlinkage long compat_sys_sched_setparam(u32 pid, struct sched_param __user *param) |
1da177e4 LT |
576 | { |
577 | return sys_sched_setparam((int)pid, param); | |
578 | } | |
579 | ||
580 | ||
581 | /* Note: it is necessary to treat pid and policy as unsigned ints, | |
582 | * with the corresponding cast to a signed int to insure that the | |
583 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
584 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
585 | */ | |
b09a4913 | 586 | asmlinkage long compat_sys_sched_setscheduler(u32 pid, u32 policy, struct sched_param __user *param) |
1da177e4 LT |
587 | { |
588 | return sys_sched_setscheduler((int)pid, (int)policy, param); | |
589 | } | |
590 | ||
591 | ||
592 | /* Note: it is necessary to treat len as an unsigned int, | |
593 | * with the corresponding cast to a signed int to insure that the | |
594 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
595 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
596 | */ | |
b09a4913 | 597 | asmlinkage long compat_sys_setdomainname(char __user *name, u32 len) |
1da177e4 LT |
598 | { |
599 | return sys_setdomainname(name, (int)len); | |
600 | } | |
601 | ||
602 | ||
603 | /* Note: it is necessary to treat gidsetsize as an unsigned int, | |
604 | * with the corresponding cast to a signed int to insure that the | |
605 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
606 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
607 | */ | |
b09a4913 | 608 | asmlinkage long compat_sys_setgroups(u32 gidsetsize, gid_t __user *grouplist) |
1da177e4 LT |
609 | { |
610 | return sys_setgroups((int)gidsetsize, grouplist); | |
611 | } | |
612 | ||
613 | ||
b09a4913 | 614 | asmlinkage long compat_sys_sethostname(char __user *name, u32 len) |
1da177e4 LT |
615 | { |
616 | /* sign extend len */ | |
617 | return sys_sethostname(name, (int)len); | |
618 | } | |
619 | ||
620 | ||
621 | /* Note: it is necessary to treat pid and pgid as unsigned ints, | |
622 | * with the corresponding cast to a signed int to insure that the | |
623 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
624 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
625 | */ | |
b09a4913 | 626 | asmlinkage long compat_sys_setpgid(u32 pid, u32 pgid) |
1da177e4 LT |
627 | { |
628 | return sys_setpgid((int)pid, (int)pgid); | |
629 | } | |
630 | ||
b09a4913 | 631 | long compat_sys_getpriority(u32 which, u32 who) |
79c2cc7b AB |
632 | { |
633 | /* sign extend which and who */ | |
634 | return sys_getpriority((int)which, (int)who); | |
635 | } | |
1da177e4 | 636 | |
b09a4913 | 637 | long compat_sys_setpriority(u32 which, u32 who, u32 niceval) |
1da177e4 LT |
638 | { |
639 | /* sign extend which, who and niceval */ | |
640 | return sys_setpriority((int)which, (int)who, (int)niceval); | |
641 | } | |
642 | ||
b09a4913 | 643 | long compat_sys_ioprio_get(u32 which, u32 who) |
79c2cc7b AB |
644 | { |
645 | /* sign extend which and who */ | |
646 | return sys_ioprio_get((int)which, (int)who); | |
647 | } | |
648 | ||
b09a4913 | 649 | long compat_sys_ioprio_set(u32 which, u32 who, u32 ioprio) |
79c2cc7b AB |
650 | { |
651 | /* sign extend which, who and ioprio */ | |
652 | return sys_ioprio_set((int)which, (int)who, (int)ioprio); | |
653 | } | |
654 | ||
1da177e4 LT |
655 | /* Note: it is necessary to treat newmask as an unsigned int, |
656 | * with the corresponding cast to a signed int to insure that the | |
657 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
658 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
659 | */ | |
b09a4913 | 660 | asmlinkage long compat_sys_ssetmask(u32 newmask) |
1da177e4 LT |
661 | { |
662 | return sys_ssetmask((int) newmask); | |
663 | } | |
664 | ||
b09a4913 | 665 | asmlinkage long compat_sys_syslog(u32 type, char __user * buf, u32 len) |
1da177e4 LT |
666 | { |
667 | /* sign extend len */ | |
668 | return sys_syslog(type, buf, (int)len); | |
669 | } | |
670 | ||
671 | ||
672 | /* Note: it is necessary to treat mask as an unsigned int, | |
673 | * with the corresponding cast to a signed int to insure that the | |
674 | * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode) | |
675 | * and the register representation of a signed int (msr in 64-bit mode) is performed. | |
676 | */ | |
b09a4913 | 677 | asmlinkage long compat_sys_umask(u32 mask) |
1da177e4 LT |
678 | { |
679 | return sys_umask((int)mask); | |
680 | } | |
681 | ||
b89a8171 | 682 | #ifdef CONFIG_SYSCTL_SYSCALL |
1da177e4 LT |
683 | struct __sysctl_args32 { |
684 | u32 name; | |
685 | int nlen; | |
686 | u32 oldval; | |
687 | u32 oldlenp; | |
688 | u32 newval; | |
689 | u32 newlen; | |
690 | u32 __unused[4]; | |
691 | }; | |
692 | ||
b09a4913 | 693 | asmlinkage long compat_sys_sysctl(struct __sysctl_args32 __user *args) |
1da177e4 LT |
694 | { |
695 | struct __sysctl_args32 tmp; | |
696 | int error; | |
697 | size_t oldlen; | |
698 | size_t __user *oldlenp = NULL; | |
699 | unsigned long addr = (((unsigned long)&args->__unused[0]) + 7) & ~7; | |
700 | ||
701 | if (copy_from_user(&tmp, args, sizeof(tmp))) | |
702 | return -EFAULT; | |
703 | ||
704 | if (tmp.oldval && tmp.oldlenp) { | |
705 | /* Duh, this is ugly and might not work if sysctl_args | |
706 | is in read-only memory, but do_sysctl does indirectly | |
707 | a lot of uaccess in both directions and we'd have to | |
708 | basically copy the whole sysctl.c here, and | |
709 | glibc's __sysctl uses rw memory for the structure | |
710 | anyway. */ | |
711 | oldlenp = (size_t __user *)addr; | |
712 | if (get_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp)) || | |
713 | put_user(oldlen, oldlenp)) | |
714 | return -EFAULT; | |
715 | } | |
716 | ||
717 | lock_kernel(); | |
718 | error = do_sysctl(compat_ptr(tmp.name), tmp.nlen, | |
719 | compat_ptr(tmp.oldval), oldlenp, | |
720 | compat_ptr(tmp.newval), tmp.newlen); | |
721 | unlock_kernel(); | |
722 | if (oldlenp) { | |
723 | if (!error) { | |
724 | if (get_user(oldlen, oldlenp) || | |
725 | put_user(oldlen, (compat_size_t __user *)compat_ptr(tmp.oldlenp))) | |
726 | error = -EFAULT; | |
727 | } | |
728 | copy_to_user(args->__unused, tmp.__unused, sizeof(tmp.__unused)); | |
729 | } | |
730 | return error; | |
731 | } | |
732 | #endif | |
733 | ||
b09a4913 | 734 | unsigned long compat_sys_mmap2(unsigned long addr, size_t len, |
1da177e4 LT |
735 | unsigned long prot, unsigned long flags, |
736 | unsigned long fd, unsigned long pgoff) | |
737 | { | |
738 | /* This should remain 12 even if PAGE_SIZE changes */ | |
739 | return sys_mmap(addr, len, prot, flags, fd, pgoff << 12); | |
740 | } | |
741 | ||
b09a4913 | 742 | long compat_sys_tgkill(u32 tgid, u32 pid, int sig) |
1da177e4 LT |
743 | { |
744 | /* sign extend tgid, pid */ | |
745 | return sys_tgkill((int)tgid, (int)pid, sig); | |
746 | } | |
747 | ||
748 | /* | |
749 | * long long munging: | |
750 | * The 32 bit ABI passes long longs in an odd even register pair. | |
751 | */ | |
752 | ||
b09a4913 | 753 | compat_ssize_t compat_sys_pread64(unsigned int fd, char __user *ubuf, compat_size_t count, |
1da177e4 LT |
754 | u32 reg6, u32 poshi, u32 poslo) |
755 | { | |
756 | return sys_pread64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo); | |
757 | } | |
758 | ||
b09a4913 | 759 | compat_ssize_t compat_sys_pwrite64(unsigned int fd, char __user *ubuf, compat_size_t count, |
1da177e4 LT |
760 | u32 reg6, u32 poshi, u32 poslo) |
761 | { | |
762 | return sys_pwrite64(fd, ubuf, count, ((loff_t)poshi << 32) | poslo); | |
763 | } | |
764 | ||
b09a4913 | 765 | compat_ssize_t compat_sys_readahead(int fd, u32 r4, u32 offhi, u32 offlo, u32 count) |
1da177e4 LT |
766 | { |
767 | return sys_readahead(fd, ((loff_t)offhi << 32) | offlo, count); | |
768 | } | |
769 | ||
b09a4913 | 770 | asmlinkage int compat_sys_truncate64(const char __user * path, u32 reg4, |
1da177e4 LT |
771 | unsigned long high, unsigned long low) |
772 | { | |
773 | return sys_truncate(path, (high << 32) | low); | |
774 | } | |
775 | ||
97ac7350 AA |
776 | asmlinkage long compat_sys_fallocate(int fd, int mode, u32 offhi, u32 offlo, |
777 | u32 lenhi, u32 lenlo) | |
778 | { | |
779 | return sys_fallocate(fd, mode, ((loff_t)offhi << 32) | offlo, | |
780 | ((loff_t)lenhi << 32) | lenlo); | |
781 | } | |
782 | ||
b09a4913 | 783 | asmlinkage int compat_sys_ftruncate64(unsigned int fd, u32 reg4, unsigned long high, |
1da177e4 LT |
784 | unsigned long low) |
785 | { | |
786 | return sys_ftruncate(fd, (high << 32) | low); | |
787 | } | |
788 | ||
789 | long ppc32_lookup_dcookie(u32 cookie_high, u32 cookie_low, char __user *buf, | |
790 | size_t len) | |
791 | { | |
792 | return sys_lookup_dcookie((u64)cookie_high << 32 | cookie_low, | |
793 | buf, len); | |
794 | } | |
795 | ||
796 | long ppc32_fadvise64(int fd, u32 unused, u32 offset_high, u32 offset_low, | |
797 | size_t len, int advice) | |
798 | { | |
799 | return sys_fadvise64(fd, (u64)offset_high << 32 | offset_low, len, | |
800 | advice); | |
801 | } | |
802 | ||
b09a4913 | 803 | asmlinkage long compat_sys_add_key(const char __user *_type, |
1da177e4 LT |
804 | const char __user *_description, |
805 | const void __user *_payload, | |
806 | u32 plen, | |
807 | u32 ringid) | |
808 | { | |
809 | return sys_add_key(_type, _description, _payload, plen, ringid); | |
810 | } | |
811 | ||
b09a4913 | 812 | asmlinkage long compat_sys_request_key(const char __user *_type, |
1da177e4 LT |
813 | const char __user *_description, |
814 | const char __user *_callout_info, | |
815 | u32 destringid) | |
816 | { | |
817 | return sys_request_key(_type, _description, _callout_info, destringid); | |
818 | } | |
819 | ||
edd5cd4a DW |
820 | asmlinkage long compat_sys_sync_file_range2(int fd, unsigned int flags, |
821 | unsigned offset_hi, unsigned offset_lo, | |
822 | unsigned nbytes_hi, unsigned nbytes_lo) | |
823 | { | |
824 | loff_t offset = ((loff_t)offset_hi << 32) | offset_lo; | |
825 | loff_t nbytes = ((loff_t)nbytes_hi << 32) | nbytes_lo; | |
826 | ||
827 | return sys_sync_file_range(fd, offset, nbytes, flags); | |
828 | } |