- update to 2.6.1-rc2 -- first cut.
[linux-flexiantxendom0-3.2.10.git] / arch / parisc / kernel / sys_parisc.c
1 /*
2  * linux/arch/parisc/kernel/sys_parisc.c
3  *
4  * this implements syscalls which are handled per-arch.
5  */
6
7 #include <asm/uaccess.h>
8 #include <linux/file.h>
9 #include <linux/fs.h>
10 #include <linux/linkage.h>
11 #include <linux/mm.h>
12 #include <linux/mman.h>
13 #include <linux/shm.h>
14 #include <linux/smp_lock.h>
15
16 int sys_pipe(int *fildes)
17 {
18         int fd[2];
19         int error;
20
21         error = do_pipe(fd);
22         if (!error) {
23                 if (copy_to_user(fildes, fd, 2*sizeof(int)))
24                         error = -EFAULT;
25         }
26         return error;
27 }
28
29 static unsigned long get_unshared_area(unsigned long addr, unsigned long len)
30 {
31         struct vm_area_struct *vma;
32
33         addr = PAGE_ALIGN(addr);
34
35         for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
36                 /* At this point:  (!vma || addr < vma->vm_end). */
37                 if (TASK_SIZE - len < addr)
38                         return -ENOMEM;
39                 if (!vma || addr + len <= vma->vm_start)
40                         return addr;
41                 addr = vma->vm_end;
42         }
43 }
44
45 #define DCACHE_ALIGN(addr) (((addr) + (SHMLBA - 1)) &~ (SHMLBA - 1))
46
47 /*
48  * We need to know the offset to use.  Old scheme was to look for
49  * existing mapping and use the same offset.  New scheme is to use the
50  * address of the kernel data structure as the seed for the offset.
51  * We'll see how that works...
52  */
53 #if 0
54 static int get_offset(struct address_space *mapping)
55 {
56         struct vm_area_struct *vma = list_entry(mapping->i_mmap_shared.next,
57                         struct vm_area_struct, shared);
58         return (vma->vm_start + ((pgoff - vma->vm_pgoff) << PAGE_SHIFT)) &
59                 (SHMLBA - 1);
60 }
61 #else
62 /* The mapping is cacheline aligned, so there's no information in the bottom
63  * few bits of the address.  We're looking for 10 bits (4MB / 4k), so let's
64  * drop the bottom 8 bits and use bits 8-17.  
65  */
66 static int get_offset(struct address_space *mapping)
67 {
68         int offset = (unsigned long) mapping << (PAGE_SHIFT - 8);
69         return offset & 0x3FF000;
70 }
71 #endif
72
73 static unsigned long get_shared_area(struct address_space *mapping,
74                 unsigned long addr, unsigned long len, unsigned long pgoff)
75 {
76         struct vm_area_struct *vma;
77         int offset = get_offset(mapping);
78
79         addr = DCACHE_ALIGN(addr - offset) + offset;
80
81         for (vma = find_vma(current->mm, addr); ; vma = vma->vm_next) {
82                 /* At this point:  (!vma || addr < vma->vm_end). */
83                 if (TASK_SIZE - len < addr)
84                         return -ENOMEM;
85                 if (!vma || addr + len <= vma->vm_start)
86                         return addr;
87                 addr = DCACHE_ALIGN(vma->vm_end - offset) + offset;
88                 if (addr < vma->vm_end) /* handle wraparound */
89                         return -ENOMEM;
90         }
91 }
92
93 unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
94                 unsigned long len, unsigned long pgoff, unsigned long flags)
95 {
96         struct inode *inode;
97
98         if (len > TASK_SIZE)
99                 return -ENOMEM;
100         if (!addr)
101                 addr = TASK_UNMAPPED_BASE;
102
103         inode = filp ? filp->f_dentry->d_inode : NULL;
104
105         if (inode && (flags & MAP_SHARED)) {
106                 addr = get_shared_area(inode->i_mapping, addr, len, pgoff);
107         } else {
108                 addr = get_unshared_area(addr, len);
109         }
110         return addr;
111 }
112
113 static unsigned long do_mmap2(unsigned long addr, unsigned long len,
114         unsigned long prot, unsigned long flags, unsigned long fd,
115         unsigned long pgoff)
116 {
117         struct file * file = NULL;
118         unsigned long error = -EBADF;
119         if (!(flags & MAP_ANONYMOUS)) {
120                 file = fget(fd);
121                 if (!file)
122                         goto out;
123         }
124
125         flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
126
127         down_write(&current->mm->mmap_sem);
128         error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
129         up_write(&current->mm->mmap_sem);
130
131         if (file != NULL)
132                 fput(file);
133 out:
134         return error;
135 }
136
137 asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
138         unsigned long prot, unsigned long flags, unsigned long fd,
139         unsigned long pgoff)
140 {
141         /* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
142            we have. */
143         return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12));
144 }
145
146 asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
147                 unsigned long prot, unsigned long flags, unsigned long fd,
148                 unsigned long offset)
149 {
150         if (!(offset & ~PAGE_MASK)) {
151                 return do_mmap2(addr, len, prot, flags, fd, offset >> PAGE_SHIFT);
152         } else {
153                 return -EINVAL;
154         }
155 }
156
157 long sys_shmat_wrapper(int shmid, char *shmaddr, int shmflag)
158 {
159         unsigned long raddr;
160         int r;
161
162         r = sys_shmat(shmid, shmaddr, shmflag, &raddr);
163         if (r < 0)
164                 return r;
165         return raddr;
166 }
167
168 /* Fucking broken ABI */
169
170 #ifdef CONFIG_PARISC64
171 extern asmlinkage long sys_truncate(const char *, unsigned long);
172 extern asmlinkage long sys_ftruncate(unsigned int, unsigned long);
173 extern asmlinkage long sys_fcntl(unsigned int, unsigned int, unsigned long);
174
175 asmlinkage long parisc_truncate64(const char * path,
176                                         unsigned int high, unsigned int low)
177 {
178         return sys_truncate(path, (long)high << 32 | low);
179 }
180
181 asmlinkage long parisc_ftruncate64(unsigned int fd,
182                                         unsigned int high, unsigned int low)
183 {
184         return sys_ftruncate(fd, (long)high << 32 | low);
185 }
186
187 /* stubs for the benefit of the syscall_table since truncate64 and truncate 
188  * are identical on LP64 */
189 asmlinkage long sys_truncate64(const char * path, unsigned long length)
190 {
191         return sys_truncate(path, length);
192 }
193 asmlinkage long sys_ftruncate64(unsigned int fd, unsigned long length)
194 {
195         return sys_ftruncate(fd, length);
196 }
197 asmlinkage long sys_fcntl64(unsigned int fd, unsigned int cmd, unsigned long arg)
198 {
199         return sys_fcntl(fd, cmd, arg);
200 }
201 #else
202
203 extern asmlinkage long sys_truncate64(const char *, loff_t);
204 extern asmlinkage long sys_ftruncate64(unsigned int, loff_t);
205
206 asmlinkage long parisc_truncate64(const char * path,
207                                         unsigned int high, unsigned int low)
208 {
209         return sys_truncate64(path, (loff_t)high << 32 | low);
210 }
211
212 asmlinkage long parisc_ftruncate64(unsigned int fd,
213                                         unsigned int high, unsigned int low)
214 {
215         return sys_ftruncate64(fd, (loff_t)high << 32 | low);
216 }
217 #endif
218
219 extern asmlinkage ssize_t sys_pread64(unsigned int fd, char *buf,
220                                         size_t count, loff_t pos);
221 extern asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char *buf,
222                                         size_t count, loff_t pos);
223 extern asmlinkage ssize_t sys_readahead(int fd, loff_t offset, size_t count);
224
225 asmlinkage ssize_t parisc_pread64(unsigned int fd, char *buf, size_t count,
226                                         unsigned int high, unsigned int low)
227 {
228         return sys_pread64(fd, buf, count, (loff_t)high << 32 | low);
229 }
230
231 asmlinkage ssize_t parisc_pwrite64(unsigned int fd, const char *buf,
232                         size_t count, unsigned int high, unsigned int low)
233 {
234         return sys_pwrite64(fd, buf, count, (loff_t)high << 32 | low);
235 }
236
237 asmlinkage ssize_t parisc_readahead(int fd, unsigned int high, unsigned int low,
238                                     size_t count)
239 {
240         return sys_readahead(fd, (loff_t)high << 32 | low, count);
241 }
242
243 /*
244  * This changes the io permissions bitmap in the current task.
245  */
246 asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on)
247 {
248         return -ENOSYS;
249 }
250
251 asmlinkage unsigned long sys_alloc_hugepages(int key, unsigned long addr, unsigned long len, int prot, int flag)
252 {
253         return -ENOMEM;
254 }
255
256 asmlinkage int sys_free_hugepages(unsigned long addr)
257 {
258         return -EINVAL;
259 }