]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
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" | |
f7fe8781 PBG |
10 | #include "linux/utsname.h" |
11 | #include "linux/personality.h" | |
1da177e4 LT |
12 | #include "asm/uaccess.h" |
13 | #define __FRAME_OFFSETS | |
14 | #include "asm/ptrace.h" | |
15 | #include "asm/unistd.h" | |
16 | #include "asm/prctl.h" /* XXX This should get the constants from libc */ | |
17 | #include "choose-mode.h" | |
ba9950c8 | 18 | #include "kern.h" |
1da177e4 | 19 | |
80f95078 PBG |
20 | asmlinkage long sys_uname64(struct new_utsname __user * name) |
21 | { | |
22 | int err; | |
23 | down_read(&uts_sem); | |
24 | err = copy_to_user(name, &system_utsname, sizeof (*name)); | |
25 | up_read(&uts_sem); | |
26 | if (personality(current->personality) == PER_LINUX32) | |
27 | err |= copy_to_user(&name->machine, "i686", 5); | |
28 | return err ? -EFAULT : 0; | |
29 | } | |
30 | ||
1da177e4 LT |
31 | #ifdef CONFIG_MODE_TT |
32 | extern int modify_ldt(int func, void *ptr, unsigned long bytecount); | |
33 | ||
34 | long sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) | |
35 | { | |
36 | /* XXX This should check VERIFY_WRITE depending on func, check this | |
37 | * in i386 as well. | |
38 | */ | |
39 | if (!access_ok(VERIFY_READ, ptr, bytecount)) | |
40 | return -EFAULT; | |
41 | return(modify_ldt(func, ptr, bytecount)); | |
42 | } | |
43 | #endif | |
44 | ||
45 | #ifdef CONFIG_MODE_SKAS | |
46 | extern int userspace_pid[]; | |
47 | ||
2d58cc9a JD |
48 | #include "skas_ptrace.h" |
49 | ||
1da177e4 LT |
50 | long sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) |
51 | { | |
52 | struct ptrace_ldt ldt; | |
53 | void *buf; | |
54 | int res, n; | |
55 | ||
56 | buf = kmalloc(bytecount, GFP_KERNEL); | |
57 | if(buf == NULL) | |
58 | return(-ENOMEM); | |
59 | ||
60 | res = 0; | |
61 | ||
62 | switch(func){ | |
63 | case 1: | |
64 | case 0x11: | |
65 | res = copy_from_user(buf, ptr, bytecount); | |
66 | break; | |
67 | } | |
68 | ||
69 | if(res != 0){ | |
70 | res = -EFAULT; | |
71 | goto out; | |
72 | } | |
73 | ||
74 | ldt = ((struct ptrace_ldt) { .func = func, | |
75 | .ptr = buf, | |
76 | .bytecount = bytecount }); | |
77 | #warning Need to look up userspace_pid by cpu | |
78 | res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt); | |
79 | if(res < 0) | |
80 | goto out; | |
81 | ||
82 | switch(func){ | |
83 | case 0: | |
84 | case 2: | |
85 | n = res; | |
86 | res = copy_to_user(ptr, buf, n); | |
87 | if(res != 0) | |
88 | res = -EFAULT; | |
89 | else | |
90 | res = n; | |
91 | break; | |
92 | } | |
93 | ||
94 | out: | |
95 | kfree(buf); | |
96 | return(res); | |
97 | } | |
98 | #endif | |
99 | ||
100 | long sys_modify_ldt(int func, void *ptr, unsigned long bytecount) | |
101 | { | |
102 | return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func, | |
103 | ptr, bytecount)); | |
104 | } | |
105 | ||
106 | #ifdef CONFIG_MODE_TT | |
107 | extern long arch_prctl(int code, unsigned long addr); | |
108 | ||
109 | static long arch_prctl_tt(int code, unsigned long addr) | |
110 | { | |
111 | unsigned long tmp; | |
112 | long ret; | |
113 | ||
114 | switch(code){ | |
115 | case ARCH_SET_GS: | |
116 | case ARCH_SET_FS: | |
117 | ret = arch_prctl(code, addr); | |
118 | break; | |
119 | case ARCH_GET_FS: | |
120 | case ARCH_GET_GS: | |
121 | ret = arch_prctl(code, (unsigned long) &tmp); | |
122 | if(!ret) | |
123 | ret = put_user(tmp, &addr); | |
124 | break; | |
125 | default: | |
126 | ret = -EINVAL; | |
127 | break; | |
128 | } | |
129 | ||
130 | return(ret); | |
131 | } | |
132 | #endif | |
133 | ||
134 | #ifdef CONFIG_MODE_SKAS | |
135 | ||
f767b02f | 136 | /* XXX: Must also call arch_prctl in the host, beside saving the segment bases! */ |
1da177e4 LT |
137 | static long arch_prctl_skas(int code, unsigned long addr) |
138 | { | |
139 | long ret = 0; | |
140 | ||
141 | switch(code){ | |
1da177e4 LT |
142 | case ARCH_SET_FS: |
143 | current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr; | |
144 | break; | |
f767b02f PBG |
145 | case ARCH_SET_GS: |
146 | current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr; | |
147 | break; | |
1da177e4 | 148 | case ARCH_GET_FS: |
f767b02f PBG |
149 | ret = put_user(current->thread.regs.regs.skas. |
150 | regs[FS_BASE / sizeof(unsigned long)], | |
151 | (unsigned long __user *)addr); | |
1da177e4 LT |
152 | break; |
153 | case ARCH_GET_GS: | |
f767b02f PBG |
154 | ret = put_user(current->thread.regs.regs.skas. |
155 | regs[GS_BASE / sizeof(unsigned long)], | |
156 | (unsigned long __user *)addr); | |
1da177e4 LT |
157 | break; |
158 | default: | |
159 | ret = -EINVAL; | |
160 | break; | |
161 | } | |
162 | ||
163 | return(ret); | |
164 | } | |
165 | #endif | |
166 | ||
167 | long sys_arch_prctl(int code, unsigned long addr) | |
168 | { | |
169 | return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr)); | |
170 | } | |
171 | ||
172 | long sys_clone(unsigned long clone_flags, unsigned long newsp, | |
173 | void __user *parent_tid, void __user *child_tid) | |
174 | { | |
175 | long ret; | |
176 | ||
e0877f07 JD |
177 | if (!newsp) |
178 | newsp = UPT_SP(¤t->thread.regs.regs); | |
1da177e4 | 179 | current->thread.forking = 1; |
e0877f07 JD |
180 | ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, |
181 | child_tid); | |
1da177e4 LT |
182 | current->thread.forking = 0; |
183 | return(ret); | |
184 | } |