File: /usr/src/linux/arch/mips/kernel/sysmips.c

1     /*
2      * MIPS specific syscalls
3      *
4      * This file is subject to the terms and conditions of the GNU General Public
5      * License.  See the file "COPYING" in the main directory of this archive
6      * for more details.
7      *
8      * Copyright (C) 1995, 1996, 1997, 2000 by Ralf Baechle
9      */
10     #include <linux/config.h>
11     #include <linux/errno.h>
12     #include <linux/linkage.h>
13     #include <linux/mm.h>
14     #include <linux/smp.h>
15     #include <linux/smp_lock.h>
16     #include <linux/sched.h>
17     #include <linux/string.h>
18     #include <linux/utsname.h>
19     
20     #include <asm/cachectl.h>
21     #include <asm/pgalloc.h>
22     #include <asm/sysmips.h>
23     #include <asm/uaccess.h>
24     
25     extern asmlinkage void syscall_trace(void);
26     
27     /*
28      * How long a hostname can we get from user space?
29      *  -EFAULT if invalid area or too long
30      *  0 if ok
31      *  >0 EFAULT after xx bytes
32      */
33     static inline int
34     get_max_hostname(unsigned long address)
35     {
36     	struct vm_area_struct * vma;
37     
38     	vma = find_vma(current->mm, address);
39     	if (!vma || vma->vm_start > address || !(vma->vm_flags & VM_READ))
40     		return -EFAULT;
41     	address = vma->vm_end - address;
42     	if (address > PAGE_SIZE)
43     		return 0;
44     	if (vma->vm_next && vma->vm_next->vm_start == vma->vm_end &&
45     	   (vma->vm_next->vm_flags & VM_READ))
46     		return 0;
47     	return address;
48     }
49     
50     asmlinkage int
51     sys_sysmips(int cmd, int arg1, int arg2, int arg3)
52     {
53     	int	*p;
54     	char	*name;
55     	int	tmp, len, retval, errno;
56     
57     	switch(cmd) {
58     	case SETNAME: {
59     		char nodename[__NEW_UTS_LEN + 1];
60     
61     		if (!capable(CAP_SYS_ADMIN))
62     			return -EPERM;
63     
64     		name = (char *) arg1;
65     
66     		len = strncpy_from_user(nodename, name, sizeof(nodename));
67     		if (len < 0) 
68     			return -EFAULT;
69     
70     		down_write(&uts_sem);
71     		strncpy(system_utsname.nodename, name, len);
72     		up_write(&uts_sem);
73     		system_utsname.nodename[len] = '\0'; 
74     		return 0;
75     	}
76     
77     	case MIPS_ATOMIC_SET: {
78     #ifdef CONFIG_CPU_HAS_LLSC
79     		unsigned int tmp;
80     
81     		p = (int *) arg1;
82     		errno = verify_area(VERIFY_WRITE, p, sizeof(*p));
83     		if (errno)
84     			return errno;
85     		errno = 0;
86     
87     		__asm__(".set\tpush\t\t\t# sysmips(MIPS_ATOMIC, ...)\n\t"
88     			".set\tmips2\n\t"
89     			".set\tnoat\n\t"
90     			"1:\tll\t%0, %4\n\t"
91     			"move\t$1, %3\n\t"
92     			"2:\tsc\t$1, %1\n\t"
93     			"beqz\t$1, 1b\n\t"
94     			".set\tpop\n\t"
95     			".section\t.fixup,\"ax\"\n"
96     			"3:\tli\t%2, 1\t\t\t# error\n\t"
97     			".previous\n\t"
98     			".section\t__ex_table,\"a\"\n\t"
99     			".word\t1b, 3b\n\t"
100     			".word\t2b, 3b\n\t"
101     			".previous\n\t"
102     			: "=&r" (tmp), "=o" (* (u32 *) p), "=r" (errno)
103     			: "r" (arg2), "o" (* (u32 *) p), "2" (errno)
104     			: "$1");
105     
106     		if (errno)
107     			return -EFAULT;
108     
109     		/* We're skipping error handling etc.  */
110     		if (current->ptrace & PT_TRACESYS)
111     			syscall_trace();
112     
113     		((struct pt_regs *)&cmd)->regs[2] = tmp;
114     		((struct pt_regs *)&cmd)->regs[7] = 0;
115     
116     		__asm__ __volatile__(
117     			"move\t$29, %0\n\t"
118     			"j\to32_ret_from_sys_call"
119     			: /* No outputs */
120     			: "r" (&cmd));
121     		/* Unreached */
122     #else
123     	printk("sys_sysmips(MIPS_ATOMIC_SET, ...) not ready for !CONFIG_CPU_HAS_LLSC\n");
124     #endif
125     	}
126     
127     	case MIPS_FIXADE:
128     		tmp = current->thread.mflags & ~3;
129     		current->thread.mflags = tmp | (arg1 & 3);
130     		retval = 0;
131     		goto out;
132     
133     	case FLUSH_CACHE:
134     		flush_cache_all();
135     		retval = 0;
136     		goto out;
137     
138     	case MIPS_RDNVRAM:
139     		retval = -EIO;
140     		goto out;
141     
142     	default:
143     		retval = -EINVAL;
144     		goto out;
145     	}
146     
147     out:
148     	return retval;
149     }
150     
151     /*
152      * No implemented yet ...
153      */
154     asmlinkage int
155     sys_cachectl(char *addr, int nbytes, int op)
156     {
157     	return -ENOSYS;
158     }
159     
160     asmlinkage int sys_pause(void)
161     {
162     	current->state = TASK_INTERRUPTIBLE;
163     	schedule();
164     	return -ERESTARTNOHAND;
165     }
166