File: /usr/src/linux/arch/ia64/kernel/sys_ia64.c

1     /*
2      * This file contains various system calls that have different calling
3      * conventions on different platforms.
4      *
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>
18     
19     #include <asm/shmparam.h>
20     #include <asm/uaccess.h>
21     
22     #define COLOR_ALIGN(addr)	(((addr) + SHMLBA - 1) & ~(SHMLBA - 1))
23     
24     unsigned long
25     arch_get_unmapped_area (struct file *filp, unsigned long addr, unsigned long len,
26     			unsigned long pgoff, unsigned long flags)
27     {
28     	struct vm_area_struct * vmm;
29     	long map_shared = (flags & MAP_SHARED);
30     
31     	if (len > RGN_MAP_LIMIT)
32     		return -ENOMEM;
33     	if (!addr)
34     		addr = TASK_UNMAPPED_BASE;
35     
36     	if (map_shared)
37     		addr = COLOR_ALIGN(addr);
38     	else
39     		addr = PAGE_ALIGN(addr);
40     
41     	for (vmm = find_vma(current->mm, addr); ; vmm = vmm->vm_next) {
42     		/* At this point:  (!vmm || addr < vmm->vm_end). */
43     		if (TASK_SIZE - len < addr)
44     			return -ENOMEM;
45     		if (rgn_offset(addr) + len > RGN_MAP_LIMIT)	/* no risk of overflow here... */
46     			return -ENOMEM;
47     		if (!vmm || addr + len <= vmm->vm_start)
48     			return addr;
49     		addr = vmm->vm_end;
50     		if (map_shared)
51     			addr = COLOR_ALIGN(addr);
52     	}
53     }
54     
55     asmlinkage long
56     ia64_getpriority (int which, int who, long arg2, long arg3, long arg4, long arg5, long arg6,
57     		  long arg7, long stack)
58     {
59     	struct pt_regs *regs = (struct pt_regs *) &stack;
60     	extern long sys_getpriority (int, int);
61     	long prio;
62     
63     	prio = sys_getpriority(which, who);
64     	if (prio >= 0) {
65     		regs->r8 = 0;	/* ensure negative priority is not mistaken as error code */
66     		prio = 20 - prio;
67     	}
68     	return prio;
69     }
70     
71     /* XXX obsolete, but leave it here until the old libc is gone... */
72     asmlinkage unsigned long
73     sys_getpagesize (void)
74     {
75     	return PAGE_SIZE;
76     }
77     
78     asmlinkage unsigned long
79     ia64_shmat (int shmid, void *shmaddr, int shmflg, long arg3, long arg4, long arg5, long arg6,
80     	    long arg7, long stack)
81     {
82     	extern int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr);
83     	struct pt_regs *regs = (struct pt_regs *) &stack;
84     	unsigned long raddr;
85     	int retval;
86     
87     	retval = sys_shmat(shmid, shmaddr, shmflg, &raddr);
88     	if (retval < 0)
89     		return retval;
90     
91     	regs->r8 = 0;	/* ensure negative addresses are not mistaken as an error code */
92     	return raddr;
93     }
94     
95     asmlinkage unsigned long
96     ia64_brk (unsigned long brk, long arg1, long arg2, long arg3,
97     	  long arg4, long arg5, long arg6, long arg7, long stack)
98     {
99     	extern int vm_enough_memory (long pages);
100     	struct pt_regs *regs = (struct pt_regs *) &stack;
101     	unsigned long rlim, retval, newbrk, oldbrk;
102     	struct mm_struct *mm = current->mm;
103     
104     	/*
105     	 * Most of this replicates the code in sys_brk() except for an additional safety
106     	 * check and the clearing of r8.  However, we can't call sys_brk() because we need
107     	 * to acquire the mmap_sem before we can do the test...
108     	 */
109     	down_write(&mm->mmap_sem);
110     
111     	if (brk < mm->end_code)
112     		goto out;
113     	newbrk = PAGE_ALIGN(brk);
114     	oldbrk = PAGE_ALIGN(mm->brk);
115     	if (oldbrk == newbrk)
116     		goto set_brk;
117     
118     	/* Always allow shrinking brk. */
119     	if (brk <= mm->brk) {
120     		if (!do_munmap(mm, newbrk, oldbrk-newbrk))
121     			goto set_brk;
122     		goto out;
123     	}
124     
125     	/* Check against unimplemented/unmapped addresses: */
126     	if ((newbrk - oldbrk) > RGN_MAP_LIMIT || rgn_offset(newbrk) > RGN_MAP_LIMIT)
127     		goto out;
128     
129     	/* Check against rlimit.. */
130     	rlim = current->rlim[RLIMIT_DATA].rlim_cur;
131     	if (rlim < RLIM_INFINITY && brk - mm->start_data > rlim)
132     		goto out;
133     
134     	/* Check against existing mmap mappings. */
135     	if (find_vma_intersection(mm, oldbrk, newbrk+PAGE_SIZE))
136     		goto out;
137     
138     	/* Check if we have enough memory.. */
139     	if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT))
140     		goto out;
141     
142     	/* Ok, looks good - let it rip. */
143     	if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)
144     		goto out;
145     set_brk:
146     	mm->brk = brk;
147     out:
148     	retval = mm->brk;
149     	up_write(&mm->mmap_sem);
150     	regs->r8 = 0;		/* ensure large retval isn't mistaken as error code */
151     	return retval;
152     }
153     
154     /*
155      * On IA-64, we return the two file descriptors in ret0 and ret1 (r8
156      * and r9) as this is faster than doing a copy_to_user().
157      */
158     asmlinkage long
159     sys_pipe (long arg0, long arg1, long arg2, long arg3,
160     	  long arg4, long arg5, long arg6, long arg7, long stack)
161     {
162     	struct pt_regs *regs = (struct pt_regs *) &stack;
163     	int fd[2];
164     	int retval;
165     
166     	retval = do_pipe(fd);
167     	if (retval)
168     		goto out;
169     	retval = fd[0];
170     	regs->r9 = fd[1];
171       out:
172     	return retval;
173     }
174     
175     static inline unsigned long
176     do_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, unsigned long pgoff)
177     {
178     	unsigned long roff;
179     	struct file *file = 0;
180     
181     	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
182     	if (!(flags & MAP_ANONYMOUS)) {
183     		file = fget(fd);
184     		if (!file)
185     			return -EBADF;
186     
187     		if (!file->f_op || !file->f_op->mmap)
188     			return -ENODEV;
189     	}
190     
191     	/*
192     	 * A zero mmap always succeeds in Linux, independent of whether or not the
193     	 * remaining arguments are valid.
194     	 */
195     	len = PAGE_ALIGN(len);
196     	if (len == 0)
197     		return addr;
198     
199     	/* don't permit mappings into unmapped space or the virtual page table of a region: */
200     	roff = rgn_offset(addr);
201     	if ((len | roff | (roff + len)) >= RGN_MAP_LIMIT)
202     		return -EINVAL;
203     
204     	/* don't permit mappings that would cross a region boundary: */
205     	if (rgn_index(addr) != rgn_index(addr + len))
206     		return -EINVAL;
207     
208     	down_write(&current->mm->mmap_sem);
209     	addr = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
210     	up_write(&current->mm->mmap_sem);
211     
212     	if (file)
213     		fput(file);
214     	return addr;
215     }
216     
217     /*
218      * mmap2() is like mmap() except that the offset is expressed in units
219      * of PAGE_SIZE (instead of bytes).  This allows to mmap2() (pieces
220      * of) files that are larger than the address space of the CPU.
221      */
222     asmlinkage unsigned long
223     sys_mmap2 (unsigned long addr, unsigned long len, int prot, int flags, int fd, long pgoff,
224     	   long arg6, long arg7, long stack)
225     {
226     	struct pt_regs *regs = (struct pt_regs *) &stack;
227     
228     	addr = do_mmap2(addr, len, prot, flags, fd, pgoff);
229     	if (!IS_ERR((void *) addr))
230     		regs->r8 = 0;	/* ensure large addresses are not mistaken as failures... */
231     	return addr;
232     }
233     
234     asmlinkage unsigned long
235     sys_mmap (unsigned long addr, unsigned long len, int prot, int flags,
236     	  int fd, long off, long arg6, long arg7, long stack)
237     {
238     	struct pt_regs *regs = (struct pt_regs *) &stack;
239     
240     	if ((off & ~PAGE_MASK) != 0)
241     		return -EINVAL;
242     
243     	addr = do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
244     	if (!IS_ERR((void *) addr))
245     		regs->r8 = 0;	/* ensure large addresses are not mistaken as failures... */
246     	return addr;
247     }
248     
249     asmlinkage long
250     sys_vm86 (long arg0, long arg1, long arg2, long arg3)
251     {
252     	printk(KERN_ERR "sys_vm86(%lx, %lx, %lx, %lx)!\n", arg0, arg1, arg2, arg3);
253     	return -ENOSYS;
254     }
255     
256     asmlinkage unsigned long
257     ia64_create_module (const char *name_user, size_t size, long arg2, long arg3,
258     		    long arg4, long arg5, long arg6, long arg7, long stack)
259     {
260     	extern unsigned long sys_create_module (const char *, size_t);
261     	struct pt_regs *regs = (struct pt_regs *) &stack;
262     	unsigned long   addr;
263     
264     	addr = sys_create_module (name_user, size);
265     	if (!IS_ERR((void *) addr))
266     		regs->r8 = 0;	/* ensure large addresses are not mistaken as failures... */
267     	return addr;
268     }
269     
270     #if 1
271     /*
272      * This is here for a while to keep compatibillity with the old stat()
273      * call - it will be removed later once everybody migrates to the new
274      * kernel stat structure that matches the glibc one - Jes
275      */
276     static __inline__ int
277     do_revalidate (struct dentry *dentry)
278     {
279     	struct inode * inode = dentry->d_inode;
280     	if (inode->i_op && inode->i_op->revalidate)
281     		return inode->i_op->revalidate(dentry);
282     	return 0;
283     }
284     
285     static int
286     cp_ia64_old_stat (struct inode *inode, struct ia64_oldstat *statbuf)
287     {
288     	struct ia64_oldstat tmp;
289     	unsigned int blocks, indirect;
290     
291     	memset(&tmp, 0, sizeof(tmp));
292     	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
293     	tmp.st_ino = inode->i_ino;
294     	tmp.st_mode = inode->i_mode;
295     	tmp.st_nlink = inode->i_nlink;
296     	SET_STAT_UID(tmp, inode->i_uid);
297     	SET_STAT_GID(tmp, inode->i_gid);
298     	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
299     	tmp.st_size = inode->i_size;
300     	tmp.st_atime = inode->i_atime;
301     	tmp.st_mtime = inode->i_mtime;
302     	tmp.st_ctime = inode->i_ctime;
303     /*
304      * st_blocks and st_blksize are approximated with a simple algorithm if
305      * they aren't supported directly by the filesystem. The minix and msdos
306      * filesystems don't keep track of blocks, so they would either have to
307      * be counted explicitly (by delving into the file itself), or by using
308      * this simple algorithm to get a reasonable (although not 100% accurate)
309      * value.
310      */
311     
312     /*
313      * Use minix fs values for the number of direct and indirect blocks.  The
314      * count is now exact for the minix fs except that it counts zero blocks.
315      * Everything is in units of BLOCK_SIZE until the assignment to
316      * tmp.st_blksize.
317      */
318     #define D_B   7
319     #define I_B   (BLOCK_SIZE / sizeof(unsigned short))
320     
321     	if (!inode->i_blksize) {
322     		blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE;
323     		if (blocks > D_B) {
324     			indirect = (blocks - D_B + I_B - 1) / I_B;
325     			blocks += indirect;
326     			if (indirect > 1) {
327     				indirect = (indirect - 1 + I_B - 1) / I_B;
328     				blocks += indirect;
329     				if (indirect > 1)
330     					blocks++;
331     			}
332     		}
333     		tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
334     		tmp.st_blksize = BLOCK_SIZE;
335     	} else {
336     		tmp.st_blocks = inode->i_blocks;
337     		tmp.st_blksize = inode->i_blksize;
338     	}
339     	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
340     }
341     
342     asmlinkage long
343     ia64_oldstat (char *filename, struct ia64_oldstat *statbuf)
344     {
345     	struct nameidata nd;
346     	int error;
347     
348     	error = user_path_walk(filename, &nd);
349     	if (!error) {
350     		error = do_revalidate(nd.dentry);
351     		if (!error)
352     		error = cp_ia64_old_stat(nd.dentry->d_inode, statbuf);
353     		path_release(&nd);
354     	}
355     	return error;
356     }
357     
358     
359     asmlinkage long
360     ia64_oldlstat (char *filename, struct ia64_oldstat *statbuf) {
361     	struct nameidata nd;
362     	int error;
363     
364     	error = user_path_walk_link(filename, &nd);
365     	if (!error) {
366     		error = do_revalidate(nd.dentry);
367     		if (!error)
368     			error = cp_ia64_old_stat(nd.dentry->d_inode, statbuf);
369     		path_release(&nd);
370     	}
371     	return error;
372     }
373     
374     asmlinkage long
375     ia64_oldfstat (unsigned int fd, struct ia64_oldstat *statbuf)
376     {
377     	struct file * f;
378     	int err = -EBADF;
379     
380     	f = fget(fd);
381     	if (f) {
382     		struct dentry * dentry = f->f_dentry;
383     
384     		err = do_revalidate(dentry);
385     		if (!err)
386     			err = cp_ia64_old_stat(dentry->d_inode, statbuf);
387     		fput(f);
388     	}
389     	return err;
390     }
391     
392     #endif
393     
394     #ifndef CONFIG_PCI
395     
396     asmlinkage long
397     sys_pciconfig_read (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len,
398     		    void *buf)
399     {
400     	return -ENOSYS;
401     }
402     
403     asmlinkage long
404     sys_pciconfig_write (unsigned long bus, unsigned long dfn, unsigned long off, unsigned long len,
405     		     void *buf)
406     {
407     	return -ENOSYS;
408     }
409     
410     #endif /* CONFIG_PCI */
411