diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/alpha/kernel/osf_sys.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/alpha/kernel/osf_sys.c')
-rw-r--r-- | arch/alpha/kernel/osf_sys.c | 1345 |
1 files changed, 1345 insertions, 0 deletions
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c new file mode 100644 index 000000000000..b5d0fd2bb10a --- /dev/null +++ b/arch/alpha/kernel/osf_sys.c | |||
@@ -0,0 +1,1345 @@ | |||
1 | /* | ||
2 | * linux/arch/alpha/kernel/osf_sys.c | ||
3 | * | ||
4 | * Copyright (C) 1995 Linus Torvalds | ||
5 | */ | ||
6 | |||
7 | /* | ||
8 | * This file handles some of the stranger OSF/1 system call interfaces. | ||
9 | * Some of the system calls expect a non-C calling standard, others have | ||
10 | * special parameter blocks.. | ||
11 | */ | ||
12 | |||
13 | #include <linux/errno.h> | ||
14 | #include <linux/sched.h> | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/mm.h> | ||
17 | #include <linux/smp.h> | ||
18 | #include <linux/smp_lock.h> | ||
19 | #include <linux/stddef.h> | ||
20 | #include <linux/syscalls.h> | ||
21 | #include <linux/unistd.h> | ||
22 | #include <linux/ptrace.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/user.h> | ||
25 | #include <linux/a.out.h> | ||
26 | #include <linux/utsname.h> | ||
27 | #include <linux/time.h> | ||
28 | #include <linux/timex.h> | ||
29 | #include <linux/major.h> | ||
30 | #include <linux/stat.h> | ||
31 | #include <linux/mman.h> | ||
32 | #include <linux/shm.h> | ||
33 | #include <linux/poll.h> | ||
34 | #include <linux/file.h> | ||
35 | #include <linux/types.h> | ||
36 | #include <linux/ipc.h> | ||
37 | #include <linux/namei.h> | ||
38 | #include <linux/uio.h> | ||
39 | #include <linux/vfs.h> | ||
40 | |||
41 | #include <asm/fpu.h> | ||
42 | #include <asm/io.h> | ||
43 | #include <asm/uaccess.h> | ||
44 | #include <asm/system.h> | ||
45 | #include <asm/sysinfo.h> | ||
46 | #include <asm/hwrpb.h> | ||
47 | #include <asm/processor.h> | ||
48 | |||
49 | extern int do_pipe(int *); | ||
50 | |||
51 | /* | ||
52 | * Brk needs to return an error. Still support Linux's brk(0) query idiom, | ||
53 | * which OSF programs just shouldn't be doing. We're still not quite | ||
54 | * identical to OSF as we don't return 0 on success, but doing otherwise | ||
55 | * would require changes to libc. Hopefully this is good enough. | ||
56 | */ | ||
57 | asmlinkage unsigned long | ||
58 | osf_brk(unsigned long brk) | ||
59 | { | ||
60 | unsigned long retval = sys_brk(brk); | ||
61 | if (brk && brk != retval) | ||
62 | retval = -ENOMEM; | ||
63 | return retval; | ||
64 | } | ||
65 | |||
66 | /* | ||
67 | * This is pure guess-work.. | ||
68 | */ | ||
69 | asmlinkage int | ||
70 | osf_set_program_attributes(unsigned long text_start, unsigned long text_len, | ||
71 | unsigned long bss_start, unsigned long bss_len) | ||
72 | { | ||
73 | struct mm_struct *mm; | ||
74 | |||
75 | lock_kernel(); | ||
76 | mm = current->mm; | ||
77 | mm->end_code = bss_start + bss_len; | ||
78 | mm->brk = bss_start + bss_len; | ||
79 | #if 0 | ||
80 | printk("set_program_attributes(%lx %lx %lx %lx)\n", | ||
81 | text_start, text_len, bss_start, bss_len); | ||
82 | #endif | ||
83 | unlock_kernel(); | ||
84 | return 0; | ||
85 | } | ||
86 | |||
87 | /* | ||
88 | * OSF/1 directory handling functions... | ||
89 | * | ||
90 | * The "getdents()" interface is much more sane: the "basep" stuff is | ||
91 | * braindamage (it can't really handle filesystems where the directory | ||
92 | * offset differences aren't the same as "d_reclen"). | ||
93 | */ | ||
94 | #define NAME_OFFSET offsetof (struct osf_dirent, d_name) | ||
95 | #define ROUND_UP(x) (((x)+3) & ~3) | ||
96 | |||
97 | struct osf_dirent { | ||
98 | unsigned int d_ino; | ||
99 | unsigned short d_reclen; | ||
100 | unsigned short d_namlen; | ||
101 | char d_name[1]; | ||
102 | }; | ||
103 | |||
104 | struct osf_dirent_callback { | ||
105 | struct osf_dirent __user *dirent; | ||
106 | long __user *basep; | ||
107 | unsigned int count; | ||
108 | int error; | ||
109 | }; | ||
110 | |||
111 | static int | ||
112 | osf_filldir(void *__buf, const char *name, int namlen, loff_t offset, | ||
113 | ino_t ino, unsigned int d_type) | ||
114 | { | ||
115 | struct osf_dirent __user *dirent; | ||
116 | struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf; | ||
117 | unsigned int reclen = ROUND_UP(NAME_OFFSET + namlen + 1); | ||
118 | |||
119 | buf->error = -EINVAL; /* only used if we fail */ | ||
120 | if (reclen > buf->count) | ||
121 | return -EINVAL; | ||
122 | if (buf->basep) { | ||
123 | if (put_user(offset, buf->basep)) | ||
124 | return -EFAULT; | ||
125 | buf->basep = NULL; | ||
126 | } | ||
127 | dirent = buf->dirent; | ||
128 | put_user(ino, &dirent->d_ino); | ||
129 | put_user(namlen, &dirent->d_namlen); | ||
130 | put_user(reclen, &dirent->d_reclen); | ||
131 | if (copy_to_user(dirent->d_name, name, namlen) || | ||
132 | put_user(0, dirent->d_name + namlen)) | ||
133 | return -EFAULT; | ||
134 | dirent = (void __user *)dirent + reclen; | ||
135 | buf->dirent = dirent; | ||
136 | buf->count -= reclen; | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | asmlinkage int | ||
141 | osf_getdirentries(unsigned int fd, struct osf_dirent __user *dirent, | ||
142 | unsigned int count, long __user *basep) | ||
143 | { | ||
144 | int error; | ||
145 | struct file *file; | ||
146 | struct osf_dirent_callback buf; | ||
147 | |||
148 | error = -EBADF; | ||
149 | file = fget(fd); | ||
150 | if (!file) | ||
151 | goto out; | ||
152 | |||
153 | buf.dirent = dirent; | ||
154 | buf.basep = basep; | ||
155 | buf.count = count; | ||
156 | buf.error = 0; | ||
157 | |||
158 | error = vfs_readdir(file, osf_filldir, &buf); | ||
159 | if (error < 0) | ||
160 | goto out_putf; | ||
161 | |||
162 | error = buf.error; | ||
163 | if (count != buf.count) | ||
164 | error = count - buf.count; | ||
165 | |||
166 | out_putf: | ||
167 | fput(file); | ||
168 | out: | ||
169 | return error; | ||
170 | } | ||
171 | |||
172 | #undef ROUND_UP | ||
173 | #undef NAME_OFFSET | ||
174 | |||
175 | asmlinkage unsigned long | ||
176 | osf_mmap(unsigned long addr, unsigned long len, unsigned long prot, | ||
177 | unsigned long flags, unsigned long fd, unsigned long off) | ||
178 | { | ||
179 | struct file *file = NULL; | ||
180 | unsigned long ret = -EBADF; | ||
181 | |||
182 | #if 0 | ||
183 | if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED)) | ||
184 | printk("%s: unimplemented OSF mmap flags %04lx\n", | ||
185 | current->comm, flags); | ||
186 | #endif | ||
187 | if (!(flags & MAP_ANONYMOUS)) { | ||
188 | file = fget(fd); | ||
189 | if (!file) | ||
190 | goto out; | ||
191 | } | ||
192 | flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); | ||
193 | down_write(¤t->mm->mmap_sem); | ||
194 | ret = do_mmap(file, addr, len, prot, flags, off); | ||
195 | up_write(¤t->mm->mmap_sem); | ||
196 | if (file) | ||
197 | fput(file); | ||
198 | out: | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | |||
203 | /* | ||
204 | * The OSF/1 statfs structure is much larger, but this should | ||
205 | * match the beginning, at least. | ||
206 | */ | ||
207 | struct osf_statfs { | ||
208 | short f_type; | ||
209 | short f_flags; | ||
210 | int f_fsize; | ||
211 | int f_bsize; | ||
212 | int f_blocks; | ||
213 | int f_bfree; | ||
214 | int f_bavail; | ||
215 | int f_files; | ||
216 | int f_ffree; | ||
217 | __kernel_fsid_t f_fsid; | ||
218 | }; | ||
219 | |||
220 | static int | ||
221 | linux_to_osf_statfs(struct kstatfs *linux_stat, struct osf_statfs __user *osf_stat, | ||
222 | unsigned long bufsiz) | ||
223 | { | ||
224 | struct osf_statfs tmp_stat; | ||
225 | |||
226 | tmp_stat.f_type = linux_stat->f_type; | ||
227 | tmp_stat.f_flags = 0; /* mount flags */ | ||
228 | tmp_stat.f_fsize = linux_stat->f_frsize; | ||
229 | tmp_stat.f_bsize = linux_stat->f_bsize; | ||
230 | tmp_stat.f_blocks = linux_stat->f_blocks; | ||
231 | tmp_stat.f_bfree = linux_stat->f_bfree; | ||
232 | tmp_stat.f_bavail = linux_stat->f_bavail; | ||
233 | tmp_stat.f_files = linux_stat->f_files; | ||
234 | tmp_stat.f_ffree = linux_stat->f_ffree; | ||
235 | tmp_stat.f_fsid = linux_stat->f_fsid; | ||
236 | if (bufsiz > sizeof(tmp_stat)) | ||
237 | bufsiz = sizeof(tmp_stat); | ||
238 | return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0; | ||
239 | } | ||
240 | |||
241 | static int | ||
242 | do_osf_statfs(struct dentry * dentry, struct osf_statfs __user *buffer, | ||
243 | unsigned long bufsiz) | ||
244 | { | ||
245 | struct kstatfs linux_stat; | ||
246 | int error = vfs_statfs(dentry->d_inode->i_sb, &linux_stat); | ||
247 | if (!error) | ||
248 | error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz); | ||
249 | return error; | ||
250 | } | ||
251 | |||
252 | asmlinkage int | ||
253 | osf_statfs(char __user *path, struct osf_statfs __user *buffer, unsigned long bufsiz) | ||
254 | { | ||
255 | struct nameidata nd; | ||
256 | int retval; | ||
257 | |||
258 | retval = user_path_walk(path, &nd); | ||
259 | if (!retval) { | ||
260 | retval = do_osf_statfs(nd.dentry, buffer, bufsiz); | ||
261 | path_release(&nd); | ||
262 | } | ||
263 | return retval; | ||
264 | } | ||
265 | |||
266 | asmlinkage int | ||
267 | osf_fstatfs(unsigned long fd, struct osf_statfs __user *buffer, unsigned long bufsiz) | ||
268 | { | ||
269 | struct file *file; | ||
270 | int retval; | ||
271 | |||
272 | retval = -EBADF; | ||
273 | file = fget(fd); | ||
274 | if (file) { | ||
275 | retval = do_osf_statfs(file->f_dentry, buffer, bufsiz); | ||
276 | fput(file); | ||
277 | } | ||
278 | return retval; | ||
279 | } | ||
280 | |||
281 | /* | ||
282 | * Uhh.. OSF/1 mount parameters aren't exactly obvious.. | ||
283 | * | ||
284 | * Although to be frank, neither are the native Linux/i386 ones.. | ||
285 | */ | ||
286 | struct ufs_args { | ||
287 | char __user *devname; | ||
288 | int flags; | ||
289 | uid_t exroot; | ||
290 | }; | ||
291 | |||
292 | struct cdfs_args { | ||
293 | char __user *devname; | ||
294 | int flags; | ||
295 | uid_t exroot; | ||
296 | |||
297 | /* This has lots more here, which Linux handles with the option block | ||
298 | but I'm too lazy to do the translation into ASCII. */ | ||
299 | }; | ||
300 | |||
301 | struct procfs_args { | ||
302 | char __user *devname; | ||
303 | int flags; | ||
304 | uid_t exroot; | ||
305 | }; | ||
306 | |||
307 | /* | ||
308 | * We can't actually handle ufs yet, so we translate UFS mounts to | ||
309 | * ext2fs mounts. I wouldn't mind a UFS filesystem, but the UFS | ||
310 | * layout is so braindead it's a major headache doing it. | ||
311 | * | ||
312 | * Just how long ago was it written? OTOH our UFS driver may be still | ||
313 | * unhappy with OSF UFS. [CHECKME] | ||
314 | */ | ||
315 | static int | ||
316 | osf_ufs_mount(char *dirname, struct ufs_args __user *args, int flags) | ||
317 | { | ||
318 | int retval; | ||
319 | struct cdfs_args tmp; | ||
320 | char *devname; | ||
321 | |||
322 | retval = -EFAULT; | ||
323 | if (copy_from_user(&tmp, args, sizeof(tmp))) | ||
324 | goto out; | ||
325 | devname = getname(tmp.devname); | ||
326 | retval = PTR_ERR(devname); | ||
327 | if (IS_ERR(devname)) | ||
328 | goto out; | ||
329 | retval = do_mount(devname, dirname, "ext2", flags, NULL); | ||
330 | putname(devname); | ||
331 | out: | ||
332 | return retval; | ||
333 | } | ||
334 | |||
335 | static int | ||
336 | osf_cdfs_mount(char *dirname, struct cdfs_args __user *args, int flags) | ||
337 | { | ||
338 | int retval; | ||
339 | struct cdfs_args tmp; | ||
340 | char *devname; | ||
341 | |||
342 | retval = -EFAULT; | ||
343 | if (copy_from_user(&tmp, args, sizeof(tmp))) | ||
344 | goto out; | ||
345 | devname = getname(tmp.devname); | ||
346 | retval = PTR_ERR(devname); | ||
347 | if (IS_ERR(devname)) | ||
348 | goto out; | ||
349 | retval = do_mount(devname, dirname, "iso9660", flags, NULL); | ||
350 | putname(devname); | ||
351 | out: | ||
352 | return retval; | ||
353 | } | ||
354 | |||
355 | static int | ||
356 | osf_procfs_mount(char *dirname, struct procfs_args __user *args, int flags) | ||
357 | { | ||
358 | struct procfs_args tmp; | ||
359 | |||
360 | if (copy_from_user(&tmp, args, sizeof(tmp))) | ||
361 | return -EFAULT; | ||
362 | |||
363 | return do_mount("", dirname, "proc", flags, NULL); | ||
364 | } | ||
365 | |||
366 | asmlinkage int | ||
367 | osf_mount(unsigned long typenr, char __user *path, int flag, void __user *data) | ||
368 | { | ||
369 | int retval = -EINVAL; | ||
370 | char *name; | ||
371 | |||
372 | lock_kernel(); | ||
373 | |||
374 | name = getname(path); | ||
375 | retval = PTR_ERR(name); | ||
376 | if (IS_ERR(name)) | ||
377 | goto out; | ||
378 | switch (typenr) { | ||
379 | case 1: | ||
380 | retval = osf_ufs_mount(name, data, flag); | ||
381 | break; | ||
382 | case 6: | ||
383 | retval = osf_cdfs_mount(name, data, flag); | ||
384 | break; | ||
385 | case 9: | ||
386 | retval = osf_procfs_mount(name, data, flag); | ||
387 | break; | ||
388 | default: | ||
389 | printk("osf_mount(%ld, %x)\n", typenr, flag); | ||
390 | } | ||
391 | putname(name); | ||
392 | out: | ||
393 | unlock_kernel(); | ||
394 | return retval; | ||
395 | } | ||
396 | |||
397 | asmlinkage int | ||
398 | osf_utsname(char __user *name) | ||
399 | { | ||
400 | int error; | ||
401 | |||
402 | down_read(&uts_sem); | ||
403 | error = -EFAULT; | ||
404 | if (copy_to_user(name + 0, system_utsname.sysname, 32)) | ||
405 | goto out; | ||
406 | if (copy_to_user(name + 32, system_utsname.nodename, 32)) | ||
407 | goto out; | ||
408 | if (copy_to_user(name + 64, system_utsname.release, 32)) | ||
409 | goto out; | ||
410 | if (copy_to_user(name + 96, system_utsname.version, 32)) | ||
411 | goto out; | ||
412 | if (copy_to_user(name + 128, system_utsname.machine, 32)) | ||
413 | goto out; | ||
414 | |||
415 | error = 0; | ||
416 | out: | ||
417 | up_read(&uts_sem); | ||
418 | return error; | ||
419 | } | ||
420 | |||
421 | asmlinkage unsigned long | ||
422 | sys_getpagesize(void) | ||
423 | { | ||
424 | return PAGE_SIZE; | ||
425 | } | ||
426 | |||
427 | asmlinkage unsigned long | ||
428 | sys_getdtablesize(void) | ||
429 | { | ||
430 | return NR_OPEN; | ||
431 | } | ||
432 | |||
433 | /* | ||
434 | * For compatibility with OSF/1 only. Use utsname(2) instead. | ||
435 | */ | ||
436 | asmlinkage int | ||
437 | osf_getdomainname(char __user *name, int namelen) | ||
438 | { | ||
439 | unsigned len; | ||
440 | int i; | ||
441 | |||
442 | if (!access_ok(VERIFY_WRITE, name, namelen)) | ||
443 | return -EFAULT; | ||
444 | |||
445 | len = namelen; | ||
446 | if (namelen > 32) | ||
447 | len = 32; | ||
448 | |||
449 | down_read(&uts_sem); | ||
450 | for (i = 0; i < len; ++i) { | ||
451 | __put_user(system_utsname.domainname[i], name + i); | ||
452 | if (system_utsname.domainname[i] == '\0') | ||
453 | break; | ||
454 | } | ||
455 | up_read(&uts_sem); | ||
456 | |||
457 | return 0; | ||
458 | } | ||
459 | |||
460 | asmlinkage long | ||
461 | osf_shmat(int shmid, void __user *shmaddr, int shmflg) | ||
462 | { | ||
463 | unsigned long raddr; | ||
464 | long err; | ||
465 | |||
466 | err = do_shmat(shmid, shmaddr, shmflg, &raddr); | ||
467 | |||
468 | /* | ||
469 | * This works because all user-level addresses are | ||
470 | * non-negative longs! | ||
471 | */ | ||
472 | return err ? err : (long)raddr; | ||
473 | } | ||
474 | |||
475 | |||
476 | /* | ||
477 | * The following stuff should move into a header file should it ever | ||
478 | * be labeled "officially supported." Right now, there is just enough | ||
479 | * support to avoid applications (such as tar) printing error | ||
480 | * messages. The attributes are not really implemented. | ||
481 | */ | ||
482 | |||
483 | /* | ||
484 | * Values for Property list entry flag | ||
485 | */ | ||
486 | #define PLE_PROPAGATE_ON_COPY 0x1 /* cp(1) will copy entry | ||
487 | by default */ | ||
488 | #define PLE_FLAG_MASK 0x1 /* Valid flag values */ | ||
489 | #define PLE_FLAG_ALL -1 /* All flag value */ | ||
490 | |||
491 | struct proplistname_args { | ||
492 | unsigned int pl_mask; | ||
493 | unsigned int pl_numnames; | ||
494 | char **pl_names; | ||
495 | }; | ||
496 | |||
497 | union pl_args { | ||
498 | struct setargs { | ||
499 | char __user *path; | ||
500 | long follow; | ||
501 | long nbytes; | ||
502 | char __user *buf; | ||
503 | } set; | ||
504 | struct fsetargs { | ||
505 | long fd; | ||
506 | long nbytes; | ||
507 | char __user *buf; | ||
508 | } fset; | ||
509 | struct getargs { | ||
510 | char __user *path; | ||
511 | long follow; | ||
512 | struct proplistname_args __user *name_args; | ||
513 | long nbytes; | ||
514 | char __user *buf; | ||
515 | int __user *min_buf_size; | ||
516 | } get; | ||
517 | struct fgetargs { | ||
518 | long fd; | ||
519 | struct proplistname_args __user *name_args; | ||
520 | long nbytes; | ||
521 | char __user *buf; | ||
522 | int __user *min_buf_size; | ||
523 | } fget; | ||
524 | struct delargs { | ||
525 | char __user *path; | ||
526 | long follow; | ||
527 | struct proplistname_args __user *name_args; | ||
528 | } del; | ||
529 | struct fdelargs { | ||
530 | long fd; | ||
531 | struct proplistname_args __user *name_args; | ||
532 | } fdel; | ||
533 | }; | ||
534 | |||
535 | enum pl_code { | ||
536 | PL_SET = 1, PL_FSET = 2, | ||
537 | PL_GET = 3, PL_FGET = 4, | ||
538 | PL_DEL = 5, PL_FDEL = 6 | ||
539 | }; | ||
540 | |||
541 | asmlinkage long | ||
542 | osf_proplist_syscall(enum pl_code code, union pl_args __user *args) | ||
543 | { | ||
544 | long error; | ||
545 | int __user *min_buf_size_ptr; | ||
546 | |||
547 | lock_kernel(); | ||
548 | switch (code) { | ||
549 | case PL_SET: | ||
550 | if (get_user(error, &args->set.nbytes)) | ||
551 | error = -EFAULT; | ||
552 | break; | ||
553 | case PL_FSET: | ||
554 | if (get_user(error, &args->fset.nbytes)) | ||
555 | error = -EFAULT; | ||
556 | break; | ||
557 | case PL_GET: | ||
558 | error = get_user(min_buf_size_ptr, &args->get.min_buf_size); | ||
559 | if (error) | ||
560 | break; | ||
561 | error = put_user(0, min_buf_size_ptr); | ||
562 | break; | ||
563 | case PL_FGET: | ||
564 | error = get_user(min_buf_size_ptr, &args->fget.min_buf_size); | ||
565 | if (error) | ||
566 | break; | ||
567 | error = put_user(0, min_buf_size_ptr); | ||
568 | break; | ||
569 | case PL_DEL: | ||
570 | case PL_FDEL: | ||
571 | error = 0; | ||
572 | break; | ||
573 | default: | ||
574 | error = -EOPNOTSUPP; | ||
575 | break; | ||
576 | }; | ||
577 | unlock_kernel(); | ||
578 | return error; | ||
579 | } | ||
580 | |||
581 | asmlinkage int | ||
582 | osf_sigstack(struct sigstack __user *uss, struct sigstack __user *uoss) | ||
583 | { | ||
584 | unsigned long usp = rdusp(); | ||
585 | unsigned long oss_sp = current->sas_ss_sp + current->sas_ss_size; | ||
586 | unsigned long oss_os = on_sig_stack(usp); | ||
587 | int error; | ||
588 | |||
589 | if (uss) { | ||
590 | void __user *ss_sp; | ||
591 | |||
592 | error = -EFAULT; | ||
593 | if (get_user(ss_sp, &uss->ss_sp)) | ||
594 | goto out; | ||
595 | |||
596 | /* If the current stack was set with sigaltstack, don't | ||
597 | swap stacks while we are on it. */ | ||
598 | error = -EPERM; | ||
599 | if (current->sas_ss_sp && on_sig_stack(usp)) | ||
600 | goto out; | ||
601 | |||
602 | /* Since we don't know the extent of the stack, and we don't | ||
603 | track onstack-ness, but rather calculate it, we must | ||
604 | presume a size. Ho hum this interface is lossy. */ | ||
605 | current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ; | ||
606 | current->sas_ss_size = SIGSTKSZ; | ||
607 | } | ||
608 | |||
609 | if (uoss) { | ||
610 | error = -EFAULT; | ||
611 | if (! access_ok(VERIFY_WRITE, uoss, sizeof(*uoss)) | ||
612 | || __put_user(oss_sp, &uoss->ss_sp) | ||
613 | || __put_user(oss_os, &uoss->ss_onstack)) | ||
614 | goto out; | ||
615 | } | ||
616 | |||
617 | error = 0; | ||
618 | out: | ||
619 | return error; | ||
620 | } | ||
621 | |||
622 | asmlinkage long | ||
623 | osf_sysinfo(int command, char __user *buf, long count) | ||
624 | { | ||
625 | static char * sysinfo_table[] = { | ||
626 | system_utsname.sysname, | ||
627 | system_utsname.nodename, | ||
628 | system_utsname.release, | ||
629 | system_utsname.version, | ||
630 | system_utsname.machine, | ||
631 | "alpha", /* instruction set architecture */ | ||
632 | "dummy", /* hardware serial number */ | ||
633 | "dummy", /* hardware manufacturer */ | ||
634 | "dummy", /* secure RPC domain */ | ||
635 | }; | ||
636 | unsigned long offset; | ||
637 | char *res; | ||
638 | long len, err = -EINVAL; | ||
639 | |||
640 | offset = command-1; | ||
641 | if (offset >= sizeof(sysinfo_table)/sizeof(char *)) { | ||
642 | /* Digital UNIX has a few unpublished interfaces here */ | ||
643 | printk("sysinfo(%d)", command); | ||
644 | goto out; | ||
645 | } | ||
646 | |||
647 | down_read(&uts_sem); | ||
648 | res = sysinfo_table[offset]; | ||
649 | len = strlen(res)+1; | ||
650 | if (len > count) | ||
651 | len = count; | ||
652 | if (copy_to_user(buf, res, len)) | ||
653 | err = -EFAULT; | ||
654 | else | ||
655 | err = 0; | ||
656 | up_read(&uts_sem); | ||
657 | out: | ||
658 | return err; | ||
659 | } | ||
660 | |||
661 | asmlinkage unsigned long | ||
662 | osf_getsysinfo(unsigned long op, void __user *buffer, unsigned long nbytes, | ||
663 | int __user *start, void __user *arg) | ||
664 | { | ||
665 | unsigned long w; | ||
666 | struct percpu_struct *cpu; | ||
667 | |||
668 | switch (op) { | ||
669 | case GSI_IEEE_FP_CONTROL: | ||
670 | /* Return current software fp control & status bits. */ | ||
671 | /* Note that DU doesn't verify available space here. */ | ||
672 | |||
673 | w = current_thread_info()->ieee_state & IEEE_SW_MASK; | ||
674 | w = swcr_update_status(w, rdfpcr()); | ||
675 | if (put_user(w, (unsigned long __user *) buffer)) | ||
676 | return -EFAULT; | ||
677 | return 0; | ||
678 | |||
679 | case GSI_IEEE_STATE_AT_SIGNAL: | ||
680 | /* | ||
681 | * Not sure anybody will ever use this weird stuff. These | ||
682 | * ops can be used (under OSF/1) to set the fpcr that should | ||
683 | * be used when a signal handler starts executing. | ||
684 | */ | ||
685 | break; | ||
686 | |||
687 | case GSI_UACPROC: | ||
688 | if (nbytes < sizeof(unsigned int)) | ||
689 | return -EINVAL; | ||
690 | w = (current_thread_info()->flags >> UAC_SHIFT) & UAC_BITMASK; | ||
691 | if (put_user(w, (unsigned int __user *)buffer)) | ||
692 | return -EFAULT; | ||
693 | return 1; | ||
694 | |||
695 | case GSI_PROC_TYPE: | ||
696 | if (nbytes < sizeof(unsigned long)) | ||
697 | return -EINVAL; | ||
698 | cpu = (struct percpu_struct*) | ||
699 | ((char*)hwrpb + hwrpb->processor_offset); | ||
700 | w = cpu->type; | ||
701 | if (put_user(w, (unsigned long __user*)buffer)) | ||
702 | return -EFAULT; | ||
703 | return 1; | ||
704 | |||
705 | case GSI_GET_HWRPB: | ||
706 | if (nbytes < sizeof(*hwrpb)) | ||
707 | return -EINVAL; | ||
708 | if (copy_to_user(buffer, hwrpb, nbytes) != 0) | ||
709 | return -EFAULT; | ||
710 | return 1; | ||
711 | |||
712 | default: | ||
713 | break; | ||
714 | } | ||
715 | |||
716 | return -EOPNOTSUPP; | ||
717 | } | ||
718 | |||
719 | asmlinkage unsigned long | ||
720 | osf_setsysinfo(unsigned long op, void __user *buffer, unsigned long nbytes, | ||
721 | int __user *start, void __user *arg) | ||
722 | { | ||
723 | switch (op) { | ||
724 | case SSI_IEEE_FP_CONTROL: { | ||
725 | unsigned long swcr, fpcr; | ||
726 | unsigned int *state; | ||
727 | |||
728 | /* | ||
729 | * Alpha Architecture Handbook 4.7.7.3: | ||
730 | * To be fully IEEE compiant, we must track the current IEEE | ||
731 | * exception state in software, because spurrious bits can be | ||
732 | * set in the trap shadow of a software-complete insn. | ||
733 | */ | ||
734 | |||
735 | if (get_user(swcr, (unsigned long __user *)buffer)) | ||
736 | return -EFAULT; | ||
737 | state = ¤t_thread_info()->ieee_state; | ||
738 | |||
739 | /* Update softare trap enable bits. */ | ||
740 | *state = (*state & ~IEEE_SW_MASK) | (swcr & IEEE_SW_MASK); | ||
741 | |||
742 | /* Update the real fpcr. */ | ||
743 | fpcr = rdfpcr() & FPCR_DYN_MASK; | ||
744 | fpcr |= ieee_swcr_to_fpcr(swcr); | ||
745 | wrfpcr(fpcr); | ||
746 | |||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | case SSI_IEEE_RAISE_EXCEPTION: { | ||
751 | unsigned long exc, swcr, fpcr, fex; | ||
752 | unsigned int *state; | ||
753 | |||
754 | if (get_user(exc, (unsigned long __user *)buffer)) | ||
755 | return -EFAULT; | ||
756 | state = ¤t_thread_info()->ieee_state; | ||
757 | exc &= IEEE_STATUS_MASK; | ||
758 | |||
759 | /* Update softare trap enable bits. */ | ||
760 | swcr = (*state & IEEE_SW_MASK) | exc; | ||
761 | *state |= exc; | ||
762 | |||
763 | /* Update the real fpcr. */ | ||
764 | fpcr = rdfpcr(); | ||
765 | fpcr |= ieee_swcr_to_fpcr(swcr); | ||
766 | wrfpcr(fpcr); | ||
767 | |||
768 | /* If any exceptions set by this call, and are unmasked, | ||
769 | send a signal. Old exceptions are not signaled. */ | ||
770 | fex = (exc >> IEEE_STATUS_TO_EXCSUM_SHIFT) & swcr; | ||
771 | if (fex) { | ||
772 | siginfo_t info; | ||
773 | int si_code = 0; | ||
774 | |||
775 | if (fex & IEEE_TRAP_ENABLE_DNO) si_code = FPE_FLTUND; | ||
776 | if (fex & IEEE_TRAP_ENABLE_INE) si_code = FPE_FLTRES; | ||
777 | if (fex & IEEE_TRAP_ENABLE_UNF) si_code = FPE_FLTUND; | ||
778 | if (fex & IEEE_TRAP_ENABLE_OVF) si_code = FPE_FLTOVF; | ||
779 | if (fex & IEEE_TRAP_ENABLE_DZE) si_code = FPE_FLTDIV; | ||
780 | if (fex & IEEE_TRAP_ENABLE_INV) si_code = FPE_FLTINV; | ||
781 | |||
782 | info.si_signo = SIGFPE; | ||
783 | info.si_errno = 0; | ||
784 | info.si_code = si_code; | ||
785 | info.si_addr = NULL; /* FIXME */ | ||
786 | send_sig_info(SIGFPE, &info, current); | ||
787 | } | ||
788 | return 0; | ||
789 | } | ||
790 | |||
791 | case SSI_IEEE_STATE_AT_SIGNAL: | ||
792 | case SSI_IEEE_IGNORE_STATE_AT_SIGNAL: | ||
793 | /* | ||
794 | * Not sure anybody will ever use this weird stuff. These | ||
795 | * ops can be used (under OSF/1) to set the fpcr that should | ||
796 | * be used when a signal handler starts executing. | ||
797 | */ | ||
798 | break; | ||
799 | |||
800 | case SSI_NVPAIRS: { | ||
801 | unsigned long v, w, i; | ||
802 | unsigned int old, new; | ||
803 | |||
804 | for (i = 0; i < nbytes; ++i) { | ||
805 | |||
806 | if (get_user(v, 2*i + (unsigned int __user *)buffer)) | ||
807 | return -EFAULT; | ||
808 | if (get_user(w, 2*i + 1 + (unsigned int __user *)buffer)) | ||
809 | return -EFAULT; | ||
810 | switch (v) { | ||
811 | case SSIN_UACPROC: | ||
812 | again: | ||
813 | old = current_thread_info()->flags; | ||
814 | new = old & ~(UAC_BITMASK << UAC_SHIFT); | ||
815 | new = new | (w & UAC_BITMASK) << UAC_SHIFT; | ||
816 | if (cmpxchg(¤t_thread_info()->flags, | ||
817 | old, new) != old) | ||
818 | goto again; | ||
819 | break; | ||
820 | |||
821 | default: | ||
822 | return -EOPNOTSUPP; | ||
823 | } | ||
824 | } | ||
825 | return 0; | ||
826 | } | ||
827 | |||
828 | default: | ||
829 | break; | ||
830 | } | ||
831 | |||
832 | return -EOPNOTSUPP; | ||
833 | } | ||
834 | |||
835 | /* Translations due to the fact that OSF's time_t is an int. Which | ||
836 | affects all sorts of things, like timeval and itimerval. */ | ||
837 | |||
838 | extern struct timezone sys_tz; | ||
839 | extern int do_adjtimex(struct timex *); | ||
840 | |||
841 | struct timeval32 | ||
842 | { | ||
843 | int tv_sec, tv_usec; | ||
844 | }; | ||
845 | |||
846 | struct itimerval32 | ||
847 | { | ||
848 | struct timeval32 it_interval; | ||
849 | struct timeval32 it_value; | ||
850 | }; | ||
851 | |||
852 | static inline long | ||
853 | get_tv32(struct timeval *o, struct timeval32 __user *i) | ||
854 | { | ||
855 | return (!access_ok(VERIFY_READ, i, sizeof(*i)) || | ||
856 | (__get_user(o->tv_sec, &i->tv_sec) | | ||
857 | __get_user(o->tv_usec, &i->tv_usec))); | ||
858 | } | ||
859 | |||
860 | static inline long | ||
861 | put_tv32(struct timeval32 __user *o, struct timeval *i) | ||
862 | { | ||
863 | return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || | ||
864 | (__put_user(i->tv_sec, &o->tv_sec) | | ||
865 | __put_user(i->tv_usec, &o->tv_usec))); | ||
866 | } | ||
867 | |||
868 | static inline long | ||
869 | get_it32(struct itimerval *o, struct itimerval32 __user *i) | ||
870 | { | ||
871 | return (!access_ok(VERIFY_READ, i, sizeof(*i)) || | ||
872 | (__get_user(o->it_interval.tv_sec, &i->it_interval.tv_sec) | | ||
873 | __get_user(o->it_interval.tv_usec, &i->it_interval.tv_usec) | | ||
874 | __get_user(o->it_value.tv_sec, &i->it_value.tv_sec) | | ||
875 | __get_user(o->it_value.tv_usec, &i->it_value.tv_usec))); | ||
876 | } | ||
877 | |||
878 | static inline long | ||
879 | put_it32(struct itimerval32 __user *o, struct itimerval *i) | ||
880 | { | ||
881 | return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) || | ||
882 | (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) | | ||
883 | __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) | | ||
884 | __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) | | ||
885 | __put_user(i->it_value.tv_usec, &o->it_value.tv_usec))); | ||
886 | } | ||
887 | |||
888 | static inline void | ||
889 | jiffies_to_timeval32(unsigned long jiffies, struct timeval32 *value) | ||
890 | { | ||
891 | value->tv_usec = (jiffies % HZ) * (1000000L / HZ); | ||
892 | value->tv_sec = jiffies / HZ; | ||
893 | } | ||
894 | |||
895 | asmlinkage int | ||
896 | osf_gettimeofday(struct timeval32 __user *tv, struct timezone __user *tz) | ||
897 | { | ||
898 | if (tv) { | ||
899 | struct timeval ktv; | ||
900 | do_gettimeofday(&ktv); | ||
901 | if (put_tv32(tv, &ktv)) | ||
902 | return -EFAULT; | ||
903 | } | ||
904 | if (tz) { | ||
905 | if (copy_to_user(tz, &sys_tz, sizeof(sys_tz))) | ||
906 | return -EFAULT; | ||
907 | } | ||
908 | return 0; | ||
909 | } | ||
910 | |||
911 | asmlinkage int | ||
912 | osf_settimeofday(struct timeval32 __user *tv, struct timezone __user *tz) | ||
913 | { | ||
914 | struct timespec kts; | ||
915 | struct timezone ktz; | ||
916 | |||
917 | if (tv) { | ||
918 | if (get_tv32((struct timeval *)&kts, tv)) | ||
919 | return -EFAULT; | ||
920 | } | ||
921 | if (tz) { | ||
922 | if (copy_from_user(&ktz, tz, sizeof(*tz))) | ||
923 | return -EFAULT; | ||
924 | } | ||
925 | |||
926 | kts.tv_nsec *= 1000; | ||
927 | |||
928 | return do_sys_settimeofday(tv ? &kts : NULL, tz ? &ktz : NULL); | ||
929 | } | ||
930 | |||
931 | asmlinkage int | ||
932 | osf_getitimer(int which, struct itimerval32 __user *it) | ||
933 | { | ||
934 | struct itimerval kit; | ||
935 | int error; | ||
936 | |||
937 | error = do_getitimer(which, &kit); | ||
938 | if (!error && put_it32(it, &kit)) | ||
939 | error = -EFAULT; | ||
940 | |||
941 | return error; | ||
942 | } | ||
943 | |||
944 | asmlinkage int | ||
945 | osf_setitimer(int which, struct itimerval32 __user *in, struct itimerval32 __user *out) | ||
946 | { | ||
947 | struct itimerval kin, kout; | ||
948 | int error; | ||
949 | |||
950 | if (in) { | ||
951 | if (get_it32(&kin, in)) | ||
952 | return -EFAULT; | ||
953 | } else | ||
954 | memset(&kin, 0, sizeof(kin)); | ||
955 | |||
956 | error = do_setitimer(which, &kin, out ? &kout : NULL); | ||
957 | if (error || !out) | ||
958 | return error; | ||
959 | |||
960 | if (put_it32(out, &kout)) | ||
961 | return -EFAULT; | ||
962 | |||
963 | return 0; | ||
964 | |||
965 | } | ||
966 | |||
967 | asmlinkage int | ||
968 | osf_utimes(char __user *filename, struct timeval32 __user *tvs) | ||
969 | { | ||
970 | struct timeval ktvs[2]; | ||
971 | |||
972 | if (tvs) { | ||
973 | if (get_tv32(&ktvs[0], &tvs[0]) || | ||
974 | get_tv32(&ktvs[1], &tvs[1])) | ||
975 | return -EFAULT; | ||
976 | } | ||
977 | |||
978 | return do_utimes(filename, tvs ? ktvs : NULL); | ||
979 | } | ||
980 | |||
981 | #define MAX_SELECT_SECONDS \ | ||
982 | ((unsigned long) (MAX_SCHEDULE_TIMEOUT / HZ)-1) | ||
983 | |||
984 | asmlinkage int | ||
985 | osf_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, | ||
986 | struct timeval32 __user *tvp) | ||
987 | { | ||
988 | fd_set_bits fds; | ||
989 | char *bits; | ||
990 | size_t size; | ||
991 | long timeout; | ||
992 | int ret = -EINVAL; | ||
993 | |||
994 | timeout = MAX_SCHEDULE_TIMEOUT; | ||
995 | if (tvp) { | ||
996 | time_t sec, usec; | ||
997 | |||
998 | if (!access_ok(VERIFY_READ, tvp, sizeof(*tvp)) | ||
999 | || __get_user(sec, &tvp->tv_sec) | ||
1000 | || __get_user(usec, &tvp->tv_usec)) { | ||
1001 | ret = -EFAULT; | ||
1002 | goto out_nofds; | ||
1003 | } | ||
1004 | |||
1005 | if (sec < 0 || usec < 0) | ||
1006 | goto out_nofds; | ||
1007 | |||
1008 | if ((unsigned long) sec < MAX_SELECT_SECONDS) { | ||
1009 | timeout = (usec + 1000000/HZ - 1) / (1000000/HZ); | ||
1010 | timeout += sec * (unsigned long) HZ; | ||
1011 | } | ||
1012 | } | ||
1013 | |||
1014 | if (n < 0 || n > current->files->max_fdset) | ||
1015 | goto out_nofds; | ||
1016 | |||
1017 | /* | ||
1018 | * We need 6 bitmaps (in/out/ex for both incoming and outgoing), | ||
1019 | * since we used fdset we need to allocate memory in units of | ||
1020 | * long-words. | ||
1021 | */ | ||
1022 | ret = -ENOMEM; | ||
1023 | size = FDS_BYTES(n); | ||
1024 | bits = kmalloc(6 * size, GFP_KERNEL); | ||
1025 | if (!bits) | ||
1026 | goto out_nofds; | ||
1027 | fds.in = (unsigned long *) bits; | ||
1028 | fds.out = (unsigned long *) (bits + size); | ||
1029 | fds.ex = (unsigned long *) (bits + 2*size); | ||
1030 | fds.res_in = (unsigned long *) (bits + 3*size); | ||
1031 | fds.res_out = (unsigned long *) (bits + 4*size); | ||
1032 | fds.res_ex = (unsigned long *) (bits + 5*size); | ||
1033 | |||
1034 | if ((ret = get_fd_set(n, inp->fds_bits, fds.in)) || | ||
1035 | (ret = get_fd_set(n, outp->fds_bits, fds.out)) || | ||
1036 | (ret = get_fd_set(n, exp->fds_bits, fds.ex))) | ||
1037 | goto out; | ||
1038 | zero_fd_set(n, fds.res_in); | ||
1039 | zero_fd_set(n, fds.res_out); | ||
1040 | zero_fd_set(n, fds.res_ex); | ||
1041 | |||
1042 | ret = do_select(n, &fds, &timeout); | ||
1043 | |||
1044 | /* OSF does not copy back the remaining time. */ | ||
1045 | |||
1046 | if (ret < 0) | ||
1047 | goto out; | ||
1048 | if (!ret) { | ||
1049 | ret = -ERESTARTNOHAND; | ||
1050 | if (signal_pending(current)) | ||
1051 | goto out; | ||
1052 | ret = 0; | ||
1053 | } | ||
1054 | |||
1055 | if (set_fd_set(n, inp->fds_bits, fds.res_in) || | ||
1056 | set_fd_set(n, outp->fds_bits, fds.res_out) || | ||
1057 | set_fd_set(n, exp->fds_bits, fds.res_ex)) | ||
1058 | ret = -EFAULT; | ||
1059 | |||
1060 | out: | ||
1061 | kfree(bits); | ||
1062 | out_nofds: | ||
1063 | return ret; | ||
1064 | } | ||
1065 | |||
1066 | struct rusage32 { | ||
1067 | struct timeval32 ru_utime; /* user time used */ | ||
1068 | struct timeval32 ru_stime; /* system time used */ | ||
1069 | long ru_maxrss; /* maximum resident set size */ | ||
1070 | long ru_ixrss; /* integral shared memory size */ | ||
1071 | long ru_idrss; /* integral unshared data size */ | ||
1072 | long ru_isrss; /* integral unshared stack size */ | ||
1073 | long ru_minflt; /* page reclaims */ | ||
1074 | long ru_majflt; /* page faults */ | ||
1075 | long ru_nswap; /* swaps */ | ||
1076 | long ru_inblock; /* block input operations */ | ||
1077 | long ru_oublock; /* block output operations */ | ||
1078 | long ru_msgsnd; /* messages sent */ | ||
1079 | long ru_msgrcv; /* messages received */ | ||
1080 | long ru_nsignals; /* signals received */ | ||
1081 | long ru_nvcsw; /* voluntary context switches */ | ||
1082 | long ru_nivcsw; /* involuntary " */ | ||
1083 | }; | ||
1084 | |||
1085 | asmlinkage int | ||
1086 | osf_getrusage(int who, struct rusage32 __user *ru) | ||
1087 | { | ||
1088 | struct rusage32 r; | ||
1089 | |||
1090 | if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) | ||
1091 | return -EINVAL; | ||
1092 | |||
1093 | memset(&r, 0, sizeof(r)); | ||
1094 | switch (who) { | ||
1095 | case RUSAGE_SELF: | ||
1096 | jiffies_to_timeval32(current->utime, &r.ru_utime); | ||
1097 | jiffies_to_timeval32(current->stime, &r.ru_stime); | ||
1098 | r.ru_minflt = current->min_flt; | ||
1099 | r.ru_majflt = current->maj_flt; | ||
1100 | break; | ||
1101 | case RUSAGE_CHILDREN: | ||
1102 | jiffies_to_timeval32(current->signal->cutime, &r.ru_utime); | ||
1103 | jiffies_to_timeval32(current->signal->cstime, &r.ru_stime); | ||
1104 | r.ru_minflt = current->signal->cmin_flt; | ||
1105 | r.ru_majflt = current->signal->cmaj_flt; | ||
1106 | break; | ||
1107 | } | ||
1108 | |||
1109 | return copy_to_user(ru, &r, sizeof(r)) ? -EFAULT : 0; | ||
1110 | } | ||
1111 | |||
1112 | asmlinkage long | ||
1113 | osf_wait4(pid_t pid, int __user *ustatus, int options, | ||
1114 | struct rusage32 __user *ur) | ||
1115 | { | ||
1116 | struct rusage r; | ||
1117 | long ret, err; | ||
1118 | mm_segment_t old_fs; | ||
1119 | |||
1120 | if (!ur) | ||
1121 | return sys_wait4(pid, ustatus, options, NULL); | ||
1122 | |||
1123 | old_fs = get_fs(); | ||
1124 | |||
1125 | set_fs (KERNEL_DS); | ||
1126 | ret = sys_wait4(pid, ustatus, options, (struct rusage __user *) &r); | ||
1127 | set_fs (old_fs); | ||
1128 | |||
1129 | if (!access_ok(VERIFY_WRITE, ur, sizeof(*ur))) | ||
1130 | return -EFAULT; | ||
1131 | |||
1132 | err = 0; | ||
1133 | err |= __put_user(r.ru_utime.tv_sec, &ur->ru_utime.tv_sec); | ||
1134 | err |= __put_user(r.ru_utime.tv_usec, &ur->ru_utime.tv_usec); | ||
1135 | err |= __put_user(r.ru_stime.tv_sec, &ur->ru_stime.tv_sec); | ||
1136 | err |= __put_user(r.ru_stime.tv_usec, &ur->ru_stime.tv_usec); | ||
1137 | err |= __put_user(r.ru_maxrss, &ur->ru_maxrss); | ||
1138 | err |= __put_user(r.ru_ixrss, &ur->ru_ixrss); | ||
1139 | err |= __put_user(r.ru_idrss, &ur->ru_idrss); | ||
1140 | err |= __put_user(r.ru_isrss, &ur->ru_isrss); | ||
1141 | err |= __put_user(r.ru_minflt, &ur->ru_minflt); | ||
1142 | err |= __put_user(r.ru_majflt, &ur->ru_majflt); | ||
1143 | err |= __put_user(r.ru_nswap, &ur->ru_nswap); | ||
1144 | err |= __put_user(r.ru_inblock, &ur->ru_inblock); | ||
1145 | err |= __put_user(r.ru_oublock, &ur->ru_oublock); | ||
1146 | err |= __put_user(r.ru_msgsnd, &ur->ru_msgsnd); | ||
1147 | err |= __put_user(r.ru_msgrcv, &ur->ru_msgrcv); | ||
1148 | err |= __put_user(r.ru_nsignals, &ur->ru_nsignals); | ||
1149 | err |= __put_user(r.ru_nvcsw, &ur->ru_nvcsw); | ||
1150 | err |= __put_user(r.ru_nivcsw, &ur->ru_nivcsw); | ||
1151 | |||
1152 | return err ? err : ret; | ||
1153 | } | ||
1154 | |||
1155 | /* | ||
1156 | * I don't know what the parameters are: the first one | ||
1157 | * seems to be a timeval pointer, and I suspect the second | ||
1158 | * one is the time remaining.. Ho humm.. No documentation. | ||
1159 | */ | ||
1160 | asmlinkage int | ||
1161 | osf_usleep_thread(struct timeval32 __user *sleep, struct timeval32 __user *remain) | ||
1162 | { | ||
1163 | struct timeval tmp; | ||
1164 | unsigned long ticks; | ||
1165 | |||
1166 | if (get_tv32(&tmp, sleep)) | ||
1167 | goto fault; | ||
1168 | |||
1169 | ticks = tmp.tv_usec; | ||
1170 | ticks = (ticks + (1000000 / HZ) - 1) / (1000000 / HZ); | ||
1171 | ticks += tmp.tv_sec * HZ; | ||
1172 | |||
1173 | current->state = TASK_INTERRUPTIBLE; | ||
1174 | ticks = schedule_timeout(ticks); | ||
1175 | |||
1176 | if (remain) { | ||
1177 | tmp.tv_sec = ticks / HZ; | ||
1178 | tmp.tv_usec = ticks % HZ; | ||
1179 | if (put_tv32(remain, &tmp)) | ||
1180 | goto fault; | ||
1181 | } | ||
1182 | |||
1183 | return 0; | ||
1184 | fault: | ||
1185 | return -EFAULT; | ||
1186 | } | ||
1187 | |||
1188 | |||
1189 | struct timex32 { | ||
1190 | unsigned int modes; /* mode selector */ | ||
1191 | long offset; /* time offset (usec) */ | ||
1192 | long freq; /* frequency offset (scaled ppm) */ | ||
1193 | long maxerror; /* maximum error (usec) */ | ||
1194 | long esterror; /* estimated error (usec) */ | ||
1195 | int status; /* clock command/status */ | ||
1196 | long constant; /* pll time constant */ | ||
1197 | long precision; /* clock precision (usec) (read only) */ | ||
1198 | long tolerance; /* clock frequency tolerance (ppm) | ||
1199 | * (read only) | ||
1200 | */ | ||
1201 | struct timeval32 time; /* (read only) */ | ||
1202 | long tick; /* (modified) usecs between clock ticks */ | ||
1203 | |||
1204 | long ppsfreq; /* pps frequency (scaled ppm) (ro) */ | ||
1205 | long jitter; /* pps jitter (us) (ro) */ | ||
1206 | int shift; /* interval duration (s) (shift) (ro) */ | ||
1207 | long stabil; /* pps stability (scaled ppm) (ro) */ | ||
1208 | long jitcnt; /* jitter limit exceeded (ro) */ | ||
1209 | long calcnt; /* calibration intervals (ro) */ | ||
1210 | long errcnt; /* calibration errors (ro) */ | ||
1211 | long stbcnt; /* stability limit exceeded (ro) */ | ||
1212 | |||
1213 | int :32; int :32; int :32; int :32; | ||
1214 | int :32; int :32; int :32; int :32; | ||
1215 | int :32; int :32; int :32; int :32; | ||
1216 | }; | ||
1217 | |||
1218 | asmlinkage int | ||
1219 | sys_old_adjtimex(struct timex32 __user *txc_p) | ||
1220 | { | ||
1221 | struct timex txc; | ||
1222 | int ret; | ||
1223 | |||
1224 | /* copy relevant bits of struct timex. */ | ||
1225 | if (copy_from_user(&txc, txc_p, offsetof(struct timex32, time)) || | ||
1226 | copy_from_user(&txc.tick, &txc_p->tick, sizeof(struct timex32) - | ||
1227 | offsetof(struct timex32, time))) | ||
1228 | return -EFAULT; | ||
1229 | |||
1230 | ret = do_adjtimex(&txc); | ||
1231 | if (ret < 0) | ||
1232 | return ret; | ||
1233 | |||
1234 | /* copy back to timex32 */ | ||
1235 | if (copy_to_user(txc_p, &txc, offsetof(struct timex32, time)) || | ||
1236 | (copy_to_user(&txc_p->tick, &txc.tick, sizeof(struct timex32) - | ||
1237 | offsetof(struct timex32, tick))) || | ||
1238 | (put_tv32(&txc_p->time, &txc.time))) | ||
1239 | return -EFAULT; | ||
1240 | |||
1241 | return ret; | ||
1242 | } | ||
1243 | |||
1244 | /* Get an address range which is currently unmapped. Similar to the | ||
1245 | generic version except that we know how to honor ADDR_LIMIT_32BIT. */ | ||
1246 | |||
1247 | static unsigned long | ||
1248 | arch_get_unmapped_area_1(unsigned long addr, unsigned long len, | ||
1249 | unsigned long limit) | ||
1250 | { | ||
1251 | struct vm_area_struct *vma = find_vma(current->mm, addr); | ||
1252 | |||
1253 | while (1) { | ||
1254 | /* At this point: (!vma || addr < vma->vm_end). */ | ||
1255 | if (limit - len < addr) | ||
1256 | return -ENOMEM; | ||
1257 | if (!vma || addr + len <= vma->vm_start) | ||
1258 | return addr; | ||
1259 | addr = vma->vm_end; | ||
1260 | vma = vma->vm_next; | ||
1261 | } | ||
1262 | } | ||
1263 | |||
1264 | unsigned long | ||
1265 | arch_get_unmapped_area(struct file *filp, unsigned long addr, | ||
1266 | unsigned long len, unsigned long pgoff, | ||
1267 | unsigned long flags) | ||
1268 | { | ||
1269 | unsigned long limit; | ||
1270 | |||
1271 | /* "32 bit" actually means 31 bit, since pointers sign extend. */ | ||
1272 | if (current->personality & ADDR_LIMIT_32BIT) | ||
1273 | limit = 0x80000000; | ||
1274 | else | ||
1275 | limit = TASK_SIZE; | ||
1276 | |||
1277 | if (len > limit) | ||
1278 | return -ENOMEM; | ||
1279 | |||
1280 | /* First, see if the given suggestion fits. | ||
1281 | |||
1282 | The OSF/1 loader (/sbin/loader) relies on us returning an | ||
1283 | address larger than the requested if one exists, which is | ||
1284 | a terribly broken way to program. | ||
1285 | |||
1286 | That said, I can see the use in being able to suggest not | ||
1287 | merely specific addresses, but regions of memory -- perhaps | ||
1288 | this feature should be incorporated into all ports? */ | ||
1289 | |||
1290 | if (addr) { | ||
1291 | addr = arch_get_unmapped_area_1 (PAGE_ALIGN(addr), len, limit); | ||
1292 | if (addr != (unsigned long) -ENOMEM) | ||
1293 | return addr; | ||
1294 | } | ||
1295 | |||
1296 | /* Next, try allocating at TASK_UNMAPPED_BASE. */ | ||
1297 | addr = arch_get_unmapped_area_1 (PAGE_ALIGN(TASK_UNMAPPED_BASE), | ||
1298 | len, limit); | ||
1299 | if (addr != (unsigned long) -ENOMEM) | ||
1300 | return addr; | ||
1301 | |||
1302 | /* Finally, try allocating in low memory. */ | ||
1303 | addr = arch_get_unmapped_area_1 (PAGE_SIZE, len, limit); | ||
1304 | |||
1305 | return addr; | ||
1306 | } | ||
1307 | |||
1308 | #ifdef CONFIG_OSF4_COMPAT | ||
1309 | |||
1310 | /* Clear top 32 bits of iov_len in the user's buffer for | ||
1311 | compatibility with old versions of OSF/1 where iov_len | ||
1312 | was defined as int. */ | ||
1313 | static int | ||
1314 | osf_fix_iov_len(const struct iovec __user *iov, unsigned long count) | ||
1315 | { | ||
1316 | unsigned long i; | ||
1317 | |||
1318 | for (i = 0 ; i < count ; i++) { | ||
1319 | int __user *iov_len_high = (int __user *)&iov[i].iov_len + 1; | ||
1320 | |||
1321 | if (put_user(0, iov_len_high)) | ||
1322 | return -EFAULT; | ||
1323 | } | ||
1324 | return 0; | ||
1325 | } | ||
1326 | |||
1327 | asmlinkage ssize_t | ||
1328 | osf_readv(unsigned long fd, const struct iovec __user * vector, unsigned long count) | ||
1329 | { | ||
1330 | if (unlikely(personality(current->personality) == PER_OSF4)) | ||
1331 | if (osf_fix_iov_len(vector, count)) | ||
1332 | return -EFAULT; | ||
1333 | return sys_readv(fd, vector, count); | ||
1334 | } | ||
1335 | |||
1336 | asmlinkage ssize_t | ||
1337 | osf_writev(unsigned long fd, const struct iovec __user * vector, unsigned long count) | ||
1338 | { | ||
1339 | if (unlikely(personality(current->personality) == PER_OSF4)) | ||
1340 | if (osf_fix_iov_len(vector, count)) | ||
1341 | return -EFAULT; | ||
1342 | return sys_writev(fd, vector, count); | ||
1343 | } | ||
1344 | |||
1345 | #endif | ||