This commit was manufactured by cvs2svn to create branch 'vserver'.
[linux-2.6.git] / arch / um / sys-x86_64 / syscalls.c
1 /*
2  * Copyright 2003 PathScale, Inc.
3  *
4  * Licensed under the GPL
5  */
6
7 #include "linux/linkage.h"
8 #include "linux/slab.h"
9 #include "linux/shm.h"
10 #include "asm/uaccess.h"
11 #define __FRAME_OFFSETS
12 #include "asm/ptrace.h"
13 #include "asm/unistd.h"
14 #include "asm/prctl.h" /* XXX This should get the constants from libc */
15 #include "choose-mode.h"
16
17 asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg)
18 {
19         unsigned long raddr;
20
21         return do_shmat(shmid, shmaddr, shmflg, &raddr) ?: (long) raddr;
22 }
23
24 #ifdef CONFIG_MODE_TT
25 extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
26
27 long sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount)
28 {
29         /* XXX This should check VERIFY_WRITE depending on func, check this
30          * in i386 as well.
31          */
32         if(verify_area(VERIFY_READ, ptr, bytecount))
33                 return(-EFAULT);
34         return(modify_ldt(func, ptr, bytecount));
35 }
36 #endif
37
38 #ifdef CONFIG_MODE_SKAS
39 extern int userspace_pid;
40
41 #ifndef __NR_mm_indirect
42 #define __NR_mm_indirect 241
43 #endif
44
45 long sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount)
46 {
47         unsigned long args[6];
48         void *buf;
49         int res, n;
50
51         buf = kmalloc(bytecount, GFP_KERNEL);
52         if(buf == NULL)
53                 return(-ENOMEM);
54
55         res = 0;
56
57         switch(func){
58         case 1:
59         case 0x11:
60                 res = copy_from_user(buf, ptr, bytecount);
61                 break;
62         }
63
64         if(res != 0){
65                 res = -EFAULT;
66                 goto out;
67         }
68
69         args[0] = func;
70         args[1] = (unsigned long) buf;
71         args[2] = bytecount;
72         res = syscall(__NR_mm_indirect, &current->mm->context.u,
73                       __NR_modify_ldt, args);
74
75         if(res < 0)
76                 goto out;
77
78         switch(func){
79         case 0:
80         case 2:
81                 n = res;
82                 res = copy_to_user(ptr, buf, n);
83                 if(res != 0)
84                         res = -EFAULT;
85                 else
86                         res = n;
87                 break;
88         }
89
90  out:
91         kfree(buf);
92         return(res);
93 }
94 #endif
95
96 long sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
97 {
98         return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func,
99                                 ptr, bytecount));
100 }
101
102 #ifdef CONFIG_MODE_TT
103 extern long arch_prctl(int code, unsigned long addr);
104
105 static long arch_prctl_tt(int code, unsigned long addr)
106 {
107         unsigned long tmp;
108         long ret;
109
110         switch(code){
111         case ARCH_SET_GS:
112         case ARCH_SET_FS:
113                 ret = arch_prctl(code, addr);
114                 break;
115         case ARCH_GET_FS:
116         case ARCH_GET_GS:
117                 ret = arch_prctl(code, (unsigned long) &tmp);
118                 if(!ret)
119                         ret = put_user(tmp, &addr);
120                 break;
121         default:
122                 ret = -EINVAL;
123                 break;
124         }
125
126         return(ret);
127 }
128 #endif
129
130 #ifdef CONFIG_MODE_SKAS
131
132 static long arch_prctl_skas(int code, unsigned long addr)
133 {
134         long ret = 0;
135
136         switch(code){
137         case ARCH_SET_GS:
138                 current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr;
139                 break;
140         case ARCH_SET_FS:
141                 current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr;
142                 break;
143         case ARCH_GET_FS:
144                 ret = put_user(current->thread.regs.regs.skas.regs[GS / sizeof(unsigned long)], &addr);
145                 break;
146         case ARCH_GET_GS:
147                 ret = put_user(current->thread.regs.regs.skas.regs[FS / sizeof(unsigned \
148 long)], &addr);
149                 break;
150         default:
151                 ret = -EINVAL;
152                 break;
153         }
154
155         return(ret);
156 }
157 #endif
158
159 long sys_arch_prctl(int code, unsigned long addr)
160 {
161         return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr));
162 }
163
164 long sys_clone(unsigned long clone_flags, unsigned long newsp,
165                void __user *parent_tid, void __user *child_tid)
166 {
167         long ret;
168
169         /* XXX: normal arch do here this pass, and also pass the regs to
170          * do_fork, instead of NULL. Currently the arch-independent code
171          * ignores these values, while the UML code (actually it's
172          * copy_thread) does the right thing. But this should change,
173          probably. */
174         /*if (!newsp)
175                 newsp = UPT_SP(current->thread.regs);*/
176         current->thread.forking = 1;
177         ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
178         current->thread.forking = 0;
179         return(ret);
180 }
181
182 /*
183  * Overrides for Emacs so that we follow Linus's tabbing style.
184  * Emacs will notice this stuff at the end of the file and automatically
185  * adjust the settings for this buffer only.  This must remain at the end
186  * of the file.
187  * ---------------------------------------------------------------------------
188  * Local variables:
189  * c-file-style: "linux"
190  * End:
191  */