Merge with 2.4.0-test3-pre4.
[linux-2.6/linux-mips.git] / arch / ia64 / kernel / sys_ia64.c
blobc25193cdcc79937aa4052069a3b830b1fdbd49be
1 /*
2 * This file contains various system calls that have different calling
3 * conventions on different platforms.
5 * Copyright (C) 1999-2000 Hewlett-Packard Co
6 * Copyright (C) 1999-2000 David Mosberger-Tang <davidm@hpl.hp.com>
7 */
8 #include <linux/config.h>
9 #include <linux/errno.h>
10 #include <linux/fs.h>
11 #include <linux/mm.h>
12 #include <linux/mman.h>
13 #include <linux/sched.h>
14 #include <linux/file.h> /* doh, must come after sched.h... */
15 #include <linux/smp.h>
16 #include <linux/smp_lock.h>
17 #include <linux/highuid.h>
19 #include <asm/uaccess.h>
21 asmlinkage long
22 ia64_getpriority (int which, int who, long arg2, long arg3, long arg4, long arg5, long arg6,
23 long arg7, long stack)
25 struct pt_regs *regs = (struct pt_regs *) &stack;
26 extern long sys_getpriority (int, int);
27 long prio;
29 prio = sys_getpriority(which, who);
30 if (prio >= 0) {
31 regs->r8 = 0; /* ensure negative priority is not mistaken as error code */
32 prio = 20 - prio;
34 return prio;
37 asmlinkage unsigned long
38 sys_getpagesize (void)
40 return PAGE_SIZE;
43 asmlinkage unsigned long
44 ia64_shmat (int shmid, void *shmaddr, int shmflg, long arg3, long arg4, long arg5, long arg6,
45 long arg7, long stack)
47 extern int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
48 struct pt_regs *regs = (struct pt_regs *) &stack;
49 unsigned long raddr;
50 int retval;
52 retval = sys_shmat(shmid, shmaddr, shmflg, &raddr);
53 if (retval < 0)
54 return retval;
56 regs->r8 = 0; /* ensure negative addresses are not mistaken as an error code */
57 return raddr;
60 asmlinkage unsigned long
61 ia64_brk (long brk, long arg1, long arg2, long arg3,
62 long arg4, long arg5, long arg6, long arg7, long stack)
64 extern unsigned long sys_brk (unsigned long brk);
65 struct pt_regs *regs = (struct pt_regs *) &stack;
66 unsigned long retval;
68 retval = sys_brk(brk);
70 regs->r8 = 0; /* ensure large retval isn't mistaken as error code */
71 return retval;
75 * On IA-64, we return the two file descriptors in ret0 and ret1 (r8
76 * and r9) as this is faster than doing a copy_to_user().
78 asmlinkage long
79 sys_pipe (long arg0, long arg1, long arg2, long arg3,
80 long arg4, long arg5, long arg6, long arg7, long stack)
82 struct pt_regs *regs = (struct pt_regs *) &stack;
83 int fd[2];
84 int retval;
86 retval = do_pipe(fd);
87 if (retval)
88 goto out;
89 retval = fd[0];
90 regs->r9 = fd[1];
91 out:
92 return retval;
95 static inline unsigned long
96 do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff)
98 long start_low, end_low, starting_region, ending_region;
99 unsigned long loff, hoff;
100 struct file *file = 0;
101 /* the virtual address space that is mappable in each region: */
102 # define OCTANT_SIZE ((PTRS_PER_PGD<<PGDIR_SHIFT)/8)
105 * A zero mmap always succeeds in Linux, independent of
106 * whether or not the remaining arguments are valid.
108 if (PAGE_ALIGN(len) == 0)
109 return addr;
111 /* Don't permit mappings into or across the address hole in a region: */
112 loff = REGION_OFFSET(addr);
113 hoff = loff - (REGION_SIZE - OCTANT_SIZE/2);
114 if ((len | loff | (loff + len)) >= OCTANT_SIZE/2
115 && (len | hoff | (hoff + len)) >= OCTANT_SIZE/2)
116 return -EINVAL;
118 /* Don't permit mappings that would cross a region boundary: */
120 starting_region = REGION_NUMBER(addr);
121 ending_region = REGION_NUMBER(addr + len);
122 if (starting_region != ending_region)
123 return -EINVAL;
125 flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
126 if (!(flags & MAP_ANONYMOUS)) {
127 file = fget(fd);
128 if (!file)
129 return -EBADF;
132 down(&current->mm->mmap_sem);
133 addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
134 up(&current->mm->mmap_sem);
136 if (file)
137 fput(file);
138 return addr;
142 * mmap2() is like mmap() except that the offset is expressed in units
143 * of PAGE_SIZE (instead of bytes). This allows to mmap2() (pieces
144 * of) files that are larger than the address space of the CPU.
146 asmlinkage unsigned long
147 sys_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, long pgoff,
148 long arg6, long arg7, long stack)
150 struct pt_regs *regs = (struct pt_regs *) &stack;
152 addr = do_mmap2(addr, len, prot, flags, fd, pgoff);
153 if (!IS_ERR(addr))
154 regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */
155 return addr;
158 asmlinkage unsigned long
159 sys_mmap (unsigned long addr, unsigned long len, int prot, int flags,
160 int fd, long off, long arg6, long arg7, long stack)
162 struct pt_regs *regs = (struct pt_regs *) &stack;
164 if ((off & ~PAGE_MASK) != 0)
165 return -EINVAL;
167 addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
168 if (!IS_ERR(addr))
169 regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */
170 return addr;
173 asmlinkage long
174 sys_ioperm (unsigned long from, unsigned long num, int on)
176 printk(KERN_ERR "sys_ioperm(from=%lx, num=%lx, on=%d)\n", from, num, on);
177 return -EIO;
180 asmlinkage long
181 sys_iopl (int level, long arg1, long arg2, long arg3)
183 lock_kernel();
184 printk(KERN_ERR "sys_iopl(level=%d)!\n", level);
185 unlock_kernel();
186 return -ENOSYS;
189 asmlinkage long
190 sys_vm86 (long arg0, long arg1, long arg2, long arg3)
192 lock_kernel();
193 printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
194 unlock_kernel();
195 return -ENOSYS;
198 asmlinkage long
199 sys_modify_ldt (long arg0, long arg1, long arg2, long arg3)
201 lock_kernel();
202 printk(KERN_ERR "sys_modify_ldt(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
203 unlock_kernel();
204 return -ENOSYS;
207 asmlinkage unsigned long
208 ia64_create_module (const char *name_user, size_t size, long arg2, long arg3,
209 long arg4, long arg5, long arg6, long arg7, long stack)
211 extern unsigned long sys_create_module (const char *, size_t);
212 struct pt_regs *regs = (struct pt_regs *) &stack;
213 unsigned long addr;
215 addr = sys_create_module (name_user, size);
216 if (!IS_ERR(addr))
217 regs->r8 = 0; /* ensure large addresses are not mistaken as failures... */
218 return addr;
221 #if 1
223 * This is here for a while to keep compatibillity with the old stat()
224 * call - it will be removed later once everybody migrates to the new
225 * kernel stat structure that matches the glibc one - Jes
227 static __inline__ int
228 do_revalidate (struct dentry *dentry)
230 struct inode * inode = dentry->d_inode;
231 if (inode->i_op && inode->i_op->revalidate)
232 return inode->i_op->revalidate(dentry);
233 return 0;
236 static int
237 cp_ia64_old_stat (struct inode *inode, struct ia64_oldstat *statbuf)
239 struct ia64_oldstat tmp;
240 unsigned int blocks, indirect;
242 memset(&tmp, 0, sizeof(tmp));
243 tmp.st_dev = kdev_t_to_nr(inode->i_dev);
244 tmp.st_ino = inode->i_ino;
245 tmp.st_mode = inode->i_mode;
246 tmp.st_nlink = inode->i_nlink;
247 SET_STAT_UID(tmp, inode->i_uid);
248 SET_STAT_GID(tmp, inode->i_gid);
249 tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
250 tmp.st_size = inode->i_size;
251 tmp.st_atime = inode->i_atime;
252 tmp.st_mtime = inode->i_mtime;
253 tmp.st_ctime = inode->i_ctime;
255 * st_blocks and st_blksize are approximated with a simple algorithm if
256 * they aren't supported directly by the filesystem. The minix and msdos
257 * filesystems don't keep track of blocks, so they would either have to
258 * be counted explicitly (by delving into the file itself), or by using
259 * this simple algorithm to get a reasonable (although not 100% accurate)
260 * value.
264 * Use minix fs values for the number of direct and indirect blocks. The
265 * count is now exact for the minix fs except that it counts zero blocks.
266 * Everything is in units of BLOCK_SIZE until the assignment to
267 * tmp.st_blksize.
269 #define D_B 7
270 #define I_B (BLOCK_SIZE / sizeof(unsigned short))
272 if (!inode->i_blksize) {
273 blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
274 if (blocks > D_B) {
275 indirect = (blocks - D_B + I_B - 1) / I_B;
276 blocks += indirect;
277 if (indirect > 1) {
278 indirect = (indirect - 1 + I_B - 1) / I_B;
279 blocks += indirect;
280 if (indirect > 1)
281 blocks++;
284 tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
285 tmp.st_blksize = BLOCK_SIZE;
286 } else {
287 tmp.st_blocks = inode->i_blocks;
288 tmp.st_blksize = inode->i_blksize;
290 return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
293 asmlinkage long
294 ia64_oldstat (char *filename, struct ia64_oldstat *statbuf)
296 struct nameidata nd;
297 int error;
299 lock_kernel();
300 error = user_path_walk(filename, &nd);
301 if (!error) {
302 error = do_revalidate(nd.dentry);
303 if (!error)
304 error = cp_ia64_old_stat(nd.dentry->d_inode, statbuf);
305 path_release(&nd);
307 unlock_kernel();
308 return error;
312 asmlinkage long
313 ia64_oldlstat (char *filename, struct ia64_oldstat *statbuf) {
314 struct nameidata nd;
315 int error;
317 lock_kernel();
318 error = user_path_walk_link(filename, &nd);
319 if (!error) {
320 error = do_revalidate(nd.dentry);
321 if (!error)
322 error = cp_ia64_old_stat(nd.dentry->d_inode, statbuf);
323 path_release(&nd);
325 unlock_kernel();
326 return error;
329 asmlinkage long
330 ia64_oldfstat (unsigned int fd, struct ia64_oldstat *statbuf)
332 struct file * f;
333 int err = -EBADF;
335 lock_kernel();
336 f = fget(fd);
337 if (f) {
338 struct dentry * dentry = f->f_dentry;
340 err = do_revalidate(dentry);
341 if (!err)
342 err = cp_ia64_old_stat(dentry->d_inode, statbuf);
343 fput(f);
345 unlock_kernel();
346 return err;
349 #endif
351 #ifndef CONFIG_PCI
353 asmlinkage long
354 sys_pciconfig_read (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len,
355 void *buf)
357 return -ENOSYS;
360 asmlinkage long
361 sys_pciconfig_write (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len,
362 void *buf)
364 return -ENOSYS;
367 #endif /* CONFIG_PCI */