Commit | Line | Data |
---|---|---|
1da177e4 | 1 | /* |
30286ef6 | 2 | * Implementation of various system calls for Linux/PowerPC |
1da177e4 | 3 | * |
1da177e4 LT |
4 | * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) |
5 | * | |
6 | * Derived from "arch/i386/kernel/sys_i386.c" | |
7 | * Adapted from the i386 version by Gary Thomas | |
8 | * Modified by Cort Dougan (cort@cs.nmt.edu) | |
9 | * and Paul Mackerras (paulus@cs.anu.edu.au). | |
10 | * | |
11 | * This file contains various random system calls that | |
12 | * have a non-standard calling sequence on the Linux/PPC | |
13 | * platform. | |
14 | * | |
15 | * This program is free software; you can redistribute it and/or | |
16 | * modify it under the terms of the GNU General Public License | |
17 | * as published by the Free Software Foundation; either version | |
18 | * 2 of the License, or (at your option) any later version. | |
19 | * | |
20 | */ | |
21 | ||
22 | #include <linux/errno.h> | |
23 | #include <linux/sched.h> | |
24 | #include <linux/syscalls.h> | |
25 | #include <linux/mm.h> | |
4e950f6f | 26 | #include <linux/fs.h> |
1da177e4 | 27 | #include <linux/smp.h> |
1da177e4 LT |
28 | #include <linux/sem.h> |
29 | #include <linux/msg.h> | |
30 | #include <linux/shm.h> | |
31 | #include <linux/stat.h> | |
32 | #include <linux/mman.h> | |
33 | #include <linux/sys.h> | |
34 | #include <linux/ipc.h> | |
35 | #include <linux/utsname.h> | |
36 | #include <linux/file.h> | |
1da177e4 LT |
37 | #include <linux/personality.h> |
38 | ||
39 | #include <asm/uaccess.h> | |
a7f31841 | 40 | #include <asm/syscalls.h> |
1da177e4 LT |
41 | #include <asm/time.h> |
42 | #include <asm/unistd.h> | |
43 | ||
30286ef6 PM |
44 | static inline unsigned long do_mmap2(unsigned long addr, size_t len, |
45 | unsigned long prot, unsigned long flags, | |
46 | unsigned long fd, unsigned long off, int shift) | |
1da177e4 | 47 | { |
05d84681 | 48 | unsigned long ret = -EINVAL; |
1da177e4 | 49 | |
ef3d3246 DK |
50 | if (!arch_validate_prot(prot)) |
51 | goto out; | |
52 | ||
30286ef6 PM |
53 | if (shift) { |
54 | if (off & ((1 << shift) - 1)) | |
55 | goto out; | |
56 | off >>= shift; | |
57 | } | |
30286ef6 | 58 | |
f8b72560 | 59 | ret = sys_mmap_pgoff(addr, len, prot, flags, fd, off); |
1da177e4 LT |
60 | out: |
61 | return ret; | |
62 | } | |
63 | ||
30286ef6 PM |
64 | unsigned long sys_mmap2(unsigned long addr, size_t len, |
65 | unsigned long prot, unsigned long flags, | |
66 | unsigned long fd, unsigned long pgoff) | |
67 | { | |
68 | return do_mmap2(addr, len, prot, flags, fd, pgoff, PAGE_SHIFT-12); | |
69 | } | |
70 | ||
71 | unsigned long sys_mmap(unsigned long addr, size_t len, | |
72 | unsigned long prot, unsigned long flags, | |
73 | unsigned long fd, off_t offset) | |
74 | { | |
75 | return do_mmap2(addr, len, prot, flags, fd, offset, PAGE_SHIFT); | |
76 | } | |
77 | ||
78 | #ifdef CONFIG_PPC32 | |
79 | /* | |
80 | * Due to some executables calling the wrong select we sometimes | |
81 | * get wrong args. This determines how the args are being passed | |
82 | * (a single ptr to them all args passed) then calls | |
83 | * sys_select() with the appropriate args. -- Cort | |
84 | */ | |
85 | int | |
86 | ppc_select(int n, fd_set __user *inp, fd_set __user *outp, fd_set __user *exp, struct timeval __user *tvp) | |
87 | { | |
88 | if ( (unsigned long)n >= 4096 ) | |
89 | { | |
90 | unsigned long __user *buffer = (unsigned long __user *)n; | |
91 | if (!access_ok(VERIFY_READ, buffer, 5*sizeof(unsigned long)) | |
92 | || __get_user(n, buffer) | |
93 | || __get_user(inp, ((fd_set __user * __user *)(buffer+1))) | |
94 | || __get_user(outp, ((fd_set __user * __user *)(buffer+2))) | |
95 | || __get_user(exp, ((fd_set __user * __user *)(buffer+3))) | |
96 | || __get_user(tvp, ((struct timeval __user * __user *)(buffer+4)))) | |
97 | return -EFAULT; | |
98 | } | |
99 | return sys_select(n, inp, outp, exp, tvp); | |
100 | } | |
101 | #endif | |
102 | ||
103 | #ifdef CONFIG_PPC64 | |
ce10d979 | 104 | long ppc64_personality(unsigned long personality) |
1da177e4 | 105 | { |
ce10d979 PM |
106 | long ret; |
107 | ||
108 | if (personality(current->personality) == PER_LINUX32 | |
7256a5d2 JK |
109 | && personality(personality) == PER_LINUX) |
110 | personality = (personality & ~PER_MASK) | PER_LINUX32; | |
ce10d979 | 111 | ret = sys_personality(personality); |
7256a5d2 JK |
112 | if (personality(ret) == PER_LINUX32) |
113 | ret = (ret & ~PER_MASK) | PER_LINUX; | |
ce10d979 | 114 | return ret; |
1da177e4 | 115 | } |
30286ef6 PM |
116 | #endif |
117 | ||
77f543cb PM |
118 | long ppc_fadvise64_64(int fd, int advice, u32 offset_high, u32 offset_low, |
119 | u32 len_high, u32 len_low) | |
120 | { | |
121 | return sys_fadvise64(fd, (u64)offset_high << 32 | offset_low, | |
122 | (u64)len_high << 32 | len_low, advice); | |
123 | } | |
529d235a ME |
124 | |
125 | long sys_switch_endian(void) | |
126 | { | |
127 | struct thread_info *ti; | |
128 | ||
129 | current->thread.regs->msr ^= MSR_LE; | |
130 | ||
131 | /* | |
132 | * Set TIF_RESTOREALL so that r3 isn't clobbered on return to | |
133 | * userspace. That also has the effect of restoring the non-volatile | |
134 | * GPRs, so we saved them on the way in here. | |
135 | */ | |
136 | ti = current_thread_info(); | |
137 | ti->flags |= _TIF_RESTOREALL; | |
138 | ||
139 | return 0; | |
140 | } |