diff options
Diffstat (limited to 'arch/um/sys-x86_64/syscalls.c')
-rw-r--r-- | arch/um/sys-x86_64/syscalls.c | 186 |
1 files changed, 186 insertions, 0 deletions
diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c new file mode 100644 index 000000000000..68205a03364c --- /dev/null +++ b/arch/um/sys-x86_64/syscalls.c | |||
@@ -0,0 +1,186 @@ | |||
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 (!access_ok(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 | long sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) | ||
42 | { | ||
43 | struct ptrace_ldt ldt; | ||
44 | void *buf; | ||
45 | int res, n; | ||
46 | |||
47 | buf = kmalloc(bytecount, GFP_KERNEL); | ||
48 | if(buf == NULL) | ||
49 | return(-ENOMEM); | ||
50 | |||
51 | res = 0; | ||
52 | |||
53 | switch(func){ | ||
54 | case 1: | ||
55 | case 0x11: | ||
56 | res = copy_from_user(buf, ptr, bytecount); | ||
57 | break; | ||
58 | } | ||
59 | |||
60 | if(res != 0){ | ||
61 | res = -EFAULT; | ||
62 | goto out; | ||
63 | } | ||
64 | |||
65 | ldt = ((struct ptrace_ldt) { .func = func, | ||
66 | .ptr = buf, | ||
67 | .bytecount = bytecount }); | ||
68 | #warning Need to look up userspace_pid by cpu | ||
69 | res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt); | ||
70 | if(res < 0) | ||
71 | goto out; | ||
72 | |||
73 | switch(func){ | ||
74 | case 0: | ||
75 | case 2: | ||
76 | n = res; | ||
77 | res = copy_to_user(ptr, buf, n); | ||
78 | if(res != 0) | ||
79 | res = -EFAULT; | ||
80 | else | ||
81 | res = n; | ||
82 | break; | ||
83 | } | ||
84 | |||
85 | out: | ||
86 | kfree(buf); | ||
87 | return(res); | ||
88 | } | ||
89 | #endif | ||
90 | |||
91 | long sys_modify_ldt(int func, void *ptr, unsigned long bytecount) | ||
92 | { | ||
93 | return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func, | ||
94 | ptr, bytecount)); | ||
95 | } | ||
96 | |||
97 | #ifdef CONFIG_MODE_TT | ||
98 | extern long arch_prctl(int code, unsigned long addr); | ||
99 | |||
100 | static long arch_prctl_tt(int code, unsigned long addr) | ||
101 | { | ||
102 | unsigned long tmp; | ||
103 | long ret; | ||
104 | |||
105 | switch(code){ | ||
106 | case ARCH_SET_GS: | ||
107 | case ARCH_SET_FS: | ||
108 | ret = arch_prctl(code, addr); | ||
109 | break; | ||
110 | case ARCH_GET_FS: | ||
111 | case ARCH_GET_GS: | ||
112 | ret = arch_prctl(code, (unsigned long) &tmp); | ||
113 | if(!ret) | ||
114 | ret = put_user(tmp, &addr); | ||
115 | break; | ||
116 | default: | ||
117 | ret = -EINVAL; | ||
118 | break; | ||
119 | } | ||
120 | |||
121 | return(ret); | ||
122 | } | ||
123 | #endif | ||
124 | |||
125 | #ifdef CONFIG_MODE_SKAS | ||
126 | |||
127 | static long arch_prctl_skas(int code, unsigned long addr) | ||
128 | { | ||
129 | long ret = 0; | ||
130 | |||
131 | switch(code){ | ||
132 | case ARCH_SET_GS: | ||
133 | current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr; | ||
134 | break; | ||
135 | case ARCH_SET_FS: | ||
136 | current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr; | ||
137 | break; | ||
138 | case ARCH_GET_FS: | ||
139 | ret = put_user(current->thread.regs.regs.skas.regs[GS / sizeof(unsigned long)], &addr); | ||
140 | break; | ||
141 | case ARCH_GET_GS: | ||
142 | ret = put_user(current->thread.regs.regs.skas.regs[FS / sizeof(unsigned \ | ||
143 | long)], &addr); | ||
144 | break; | ||
145 | default: | ||
146 | ret = -EINVAL; | ||
147 | break; | ||
148 | } | ||
149 | |||
150 | return(ret); | ||
151 | } | ||
152 | #endif | ||
153 | |||
154 | long sys_arch_prctl(int code, unsigned long addr) | ||
155 | { | ||
156 | return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr)); | ||
157 | } | ||
158 | |||
159 | long sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
160 | void __user *parent_tid, void __user *child_tid) | ||
161 | { | ||
162 | long ret; | ||
163 | |||
164 | /* XXX: normal arch do here this pass, and also pass the regs to | ||
165 | * do_fork, instead of NULL. Currently the arch-independent code | ||
166 | * ignores these values, while the UML code (actually it's | ||
167 | * copy_thread) does the right thing. But this should change, | ||
168 | probably. */ | ||
169 | /*if (!newsp) | ||
170 | newsp = UPT_SP(current->thread.regs);*/ | ||
171 | current->thread.forking = 1; | ||
172 | ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid); | ||
173 | current->thread.forking = 0; | ||
174 | return(ret); | ||
175 | } | ||
176 | |||
177 | /* | ||
178 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
179 | * Emacs will notice this stuff at the end of the file and automatically | ||
180 | * adjust the settings for this buffer only. This must remain at the end | ||
181 | * of the file. | ||
182 | * --------------------------------------------------------------------------- | ||
183 | * Local variables: | ||
184 | * c-file-style: "linux" | ||
185 | * End: | ||
186 | */ | ||