blob: 15768c96ceb4b176382d378767954c09f06ae89f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
Paolo 'Blaisorblade' Giarrusso80f95072005-05-01 08:58:55 -070017/* XXX: copied from x86-64: arch/x86_64/kernel/sys_x86_64.c */
Linus Torvalds1da177e2005-04-16 15:20:36 -070018asmlinkage long wrap_sys_shmat(int shmid, char __user *shmaddr, int shmflg)
19{
20 unsigned long raddr;
21
22 return do_shmat(shmid, shmaddr, shmflg, &raddr) ?: (long) raddr;
23}
24
Paolo 'Blaisorblade' Giarrusso80f95072005-05-01 08:58:55 -070025asmlinkage long sys_uname64(struct new_utsname __user * name)
26{
27 int err;
28 down_read(&uts_sem);
29 err = copy_to_user(name, &system_utsname, sizeof (*name));
30 up_read(&uts_sem);
31 if (personality(current->personality) == PER_LINUX32)
32 err |= copy_to_user(&name->machine, "i686", 5);
33 return err ? -EFAULT : 0;
34}
35
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#ifdef CONFIG_MODE_TT
37extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
38
39long sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount)
40{
41 /* XXX This should check VERIFY_WRITE depending on func, check this
42 * in i386 as well.
43 */
44 if (!access_ok(VERIFY_READ, ptr, bytecount))
45 return -EFAULT;
46 return(modify_ldt(func, ptr, bytecount));
47}
48#endif
49
50#ifdef CONFIG_MODE_SKAS
51extern int userspace_pid[];
52
53long sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount)
54{
55 struct ptrace_ldt ldt;
56 void *buf;
57 int res, n;
58
59 buf = kmalloc(bytecount, GFP_KERNEL);
60 if(buf == NULL)
61 return(-ENOMEM);
62
63 res = 0;
64
65 switch(func){
66 case 1:
67 case 0x11:
68 res = copy_from_user(buf, ptr, bytecount);
69 break;
70 }
71
72 if(res != 0){
73 res = -EFAULT;
74 goto out;
75 }
76
77 ldt = ((struct ptrace_ldt) { .func = func,
78 .ptr = buf,
79 .bytecount = bytecount });
80#warning Need to look up userspace_pid by cpu
81 res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt);
82 if(res < 0)
83 goto out;
84
85 switch(func){
86 case 0:
87 case 2:
88 n = res;
89 res = copy_to_user(ptr, buf, n);
90 if(res != 0)
91 res = -EFAULT;
92 else
93 res = n;
94 break;
95 }
96
97 out:
98 kfree(buf);
99 return(res);
100}
101#endif
102
103long sys_modify_ldt(int func, void *ptr, unsigned long bytecount)
104{
105 return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func,
106 ptr, bytecount));
107}
108
109#ifdef CONFIG_MODE_TT
110extern long arch_prctl(int code, unsigned long addr);
111
112static long arch_prctl_tt(int code, unsigned long addr)
113{
114 unsigned long tmp;
115 long ret;
116
117 switch(code){
118 case ARCH_SET_GS:
119 case ARCH_SET_FS:
120 ret = arch_prctl(code, addr);
121 break;
122 case ARCH_GET_FS:
123 case ARCH_GET_GS:
124 ret = arch_prctl(code, (unsigned long) &tmp);
125 if(!ret)
126 ret = put_user(tmp, &addr);
127 break;
128 default:
129 ret = -EINVAL;
130 break;
131 }
132
133 return(ret);
134}
135#endif
136
137#ifdef CONFIG_MODE_SKAS
138
139static long arch_prctl_skas(int code, unsigned long addr)
140{
141 long ret = 0;
142
143 switch(code){
144 case ARCH_SET_GS:
145 current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr;
146 break;
147 case ARCH_SET_FS:
148 current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr;
149 break;
150 case ARCH_GET_FS:
151 ret = put_user(current->thread.regs.regs.skas.regs[GS / sizeof(unsigned long)], &addr);
152 break;
153 case ARCH_GET_GS:
154 ret = put_user(current->thread.regs.regs.skas.regs[FS / sizeof(unsigned \
155long)], &addr);
156 break;
157 default:
158 ret = -EINVAL;
159 break;
160 }
161
162 return(ret);
163}
164#endif
165
166long sys_arch_prctl(int code, unsigned long addr)
167{
168 return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr));
169}
170
171long sys_clone(unsigned long clone_flags, unsigned long newsp,
172 void __user *parent_tid, void __user *child_tid)
173{
174 long ret;
175
176 /* XXX: normal arch do here this pass, and also pass the regs to
177 * do_fork, instead of NULL. Currently the arch-independent code
178 * ignores these values, while the UML code (actually it's
179 * copy_thread) does the right thing. But this should change,
180 probably. */
181 /*if (!newsp)
182 newsp = UPT_SP(current->thread.regs);*/
183 current->thread.forking = 1;
184 ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
185 current->thread.forking = 0;
186 return(ret);
187}
188
189/*
190 * Overrides for Emacs so that we follow Linus's tabbing style.
191 * Emacs will notice this stuff at the end of the file and automatically
192 * adjust the settings for this buffer only. This must remain at the end
193 * of the file.
194 * ---------------------------------------------------------------------------
195 * Local variables:
196 * c-file-style: "linux"
197 * End:
198 */