1 /* $OpenBSD: linux_sched.c,v 1.5 2004/11/23 19:08:52 miod Exp $ */
2 /* $NetBSD: linux_sched.c,v 1.6 2000/05/28 05:49:05 thorpej Exp $ */
3
4 /*-
5 * Copyright (c) 1999 The NetBSD Foundation, Inc.
6 * All rights reserved.
7 *
8 * This code is derived from software contributed to The NetBSD Foundation
9 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
10 * NASA Ames Research Center; by Matthias Scheler.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. All advertising materials mentioning features or use of this software
21 * must display the following acknowledgement:
22 * This product includes software developed by the NetBSD
23 * Foundation, Inc. and its contributors.
24 * 4. Neither the name of The NetBSD Foundation nor the names of its
25 * contributors may be used to endorse or promote products derived
26 * from this software without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 * POSSIBILITY OF SUCH DAMAGE.
39 */
40
41 /*
42 * Linux compatibility module. Try to deal with scheduler related syscalls.
43 */
44
45 #include <sys/types.h>
46 #include <sys/param.h>
47 #include <sys/mount.h>
48 #include <sys/proc.h>
49 #include <sys/systm.h>
50 #include <sys/syscallargs.h>
51
52 #include <machine/cpu.h>
53
54 #include <compat/linux/linux_types.h>
55 #include <compat/linux/linux_sched.h>
56 #include <compat/linux/linux_signal.h>
57 #include <compat/linux/linux_syscallargs.h>
58
59 int
60 linux_sys_clone(p, v, retval)
61 struct proc *p;
62 void *v;
63 register_t *retval;
64 {
65 struct linux_sys_clone_args /* {
66 syscallarg(int) flags;
67 syscallarg(void *) stack;
68 } */ *uap = v;
69 int flags = FORK_RFORK, sig;
70
71 /*
72 * We don't support the Linux CLONE_PID or CLONE_PTRACE flags.
73 */
74 if (SCARG(uap, flags) & (LINUX_CLONE_PID | LINUX_CLONE_PTRACE))
75 return (EINVAL);
76
77 if (SCARG(uap, flags) & LINUX_CLONE_VM)
78 flags |= FORK_SHAREVM;
79 /* XXX We pretend to support CLONE_FS for the moment. */
80 if (SCARG(uap, flags) & LINUX_CLONE_FILES)
81 flags |= FORK_SHAREFILES;
82 if (SCARG(uap, flags) & LINUX_CLONE_SIGHAND)
83 flags |= FORK_SIGHAND;
84 if (SCARG(uap, flags) & LINUX_CLONE_VFORK) {
85 flags |= FORK_PPWAIT;
86 }
87
88 sig = SCARG(uap, flags) & LINUX_CLONE_CSIGNAL;
89 if (sig < 0 || sig >= LINUX__NSIG)
90 return (EINVAL);
91 sig = linux_to_bsd_sig[sig];
92
93 /*
94 * Note that Linux does not provide a portable way of specifying
95 * the stack area; the caller must know if the stack grows up
96 * or down. So, we pass a stack size of 0, so that the code
97 * that makes this adjustment is a noop.
98 */
99 return (fork1(p, sig, flags, SCARG(uap, stack), 0, NULL, NULL, retval,
100 NULL));
101 }
102
103 int
104 linux_sys_sched_setparam(cp, v, retval)
105 struct proc *cp;
106 void *v;
107 register_t *retval;
108 {
109 struct linux_sys_sched_setparam_args /* {
110 syscallarg(linux_pid_t) pid;
111 syscallarg(const struct linux_sched_param *) sp;
112 } */ *uap = v;
113 int error;
114 struct linux_sched_param lp;
115 struct proc *p;
116
117 /*
118 * We only check for valid parameters and return afterwards.
119 */
120
121 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
122 return (EINVAL);
123
124 error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
125 if (error)
126 return (error);
127
128 if (SCARG(uap, pid) != 0) {
129 struct pcred *pc = cp->p_cred;
130
131 if ((p = pfind(SCARG(uap, pid))) == NULL)
132 return (ESRCH);
133 if (!(cp == p ||
134 pc->pc_ucred->cr_uid == 0 ||
135 pc->p_ruid == p->p_cred->p_ruid ||
136 pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
137 pc->p_ruid == p->p_ucred->cr_uid ||
138 pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
139 return (EPERM);
140 }
141
142 return (0);
143 }
144
145 int
146 linux_sys_sched_getparam(cp, v, retval)
147 struct proc *cp;
148 void *v;
149 register_t *retval;
150 {
151 struct linux_sys_sched_getparam_args /* {
152 syscallarg(linux_pid_t) pid;
153 syscallarg(struct linux_sched_param *) sp;
154 } */ *uap = v;
155 struct proc *p;
156 struct linux_sched_param lp;
157
158 /*
159 * We only check for valid parameters and return a dummy priority
160 * afterwards.
161 */
162 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
163 return (EINVAL);
164
165 if (SCARG(uap, pid) != 0) {
166 struct pcred *pc = cp->p_cred;
167
168 if ((p = pfind(SCARG(uap, pid))) == NULL)
169 return (ESRCH);
170 if (!(cp == p ||
171 pc->pc_ucred->cr_uid == 0 ||
172 pc->p_ruid == p->p_cred->p_ruid ||
173 pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
174 pc->p_ruid == p->p_ucred->cr_uid ||
175 pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
176 return (EPERM);
177 }
178
179 lp.sched_priority = 0;
180 return (copyout(&lp, SCARG(uap, sp), sizeof lp));
181 }
182
183 int
184 linux_sys_sched_setscheduler(cp, v, retval)
185 struct proc *cp;
186 void *v;
187 register_t *retval;
188 {
189 struct linux_sys_sched_setscheduler_args /* {
190 syscallarg(linux_pid_t) pid;
191 syscallarg(int) policy;
192 syscallarg(cont struct linux_sched_scheduler *) sp;
193 } */ *uap = v;
194 int error;
195 struct linux_sched_param lp;
196 struct proc *p;
197
198 /*
199 * We only check for valid parameters and return afterwards.
200 */
201
202 if (SCARG(uap, pid) < 0 || SCARG(uap, sp) == NULL)
203 return (EINVAL);
204
205 error = copyin(SCARG(uap, sp), &lp, sizeof(lp));
206 if (error)
207 return (error);
208
209 if (SCARG(uap, pid) != 0) {
210 struct pcred *pc = cp->p_cred;
211
212 if ((p = pfind(SCARG(uap, pid))) == NULL)
213 return (ESRCH);
214 if (!(cp == p ||
215 pc->pc_ucred->cr_uid == 0 ||
216 pc->p_ruid == p->p_cred->p_ruid ||
217 pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
218 pc->p_ruid == p->p_ucred->cr_uid ||
219 pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
220 return (EPERM);
221 }
222
223 /*
224 * We can't emulate anything but the default scheduling policy.
225 */
226 if (SCARG(uap, policy) != LINUX_SCHED_OTHER || lp.sched_priority != 0)
227 return (EINVAL);
228
229 return (0);
230 }
231
232 int
233 linux_sys_sched_getscheduler(cp, v, retval)
234 struct proc *cp;
235 void *v;
236 register_t *retval;
237 {
238 struct linux_sys_sched_getscheduler_args /* {
239 syscallarg(linux_pid_t) pid;
240 } */ *uap = v;
241 struct proc *p;
242
243 *retval = -1;
244
245 /*
246 * We only check for valid parameters and return afterwards.
247 */
248
249 if (SCARG(uap, pid) != 0) {
250 struct pcred *pc = cp->p_cred;
251
252 if ((p = pfind(SCARG(uap, pid))) == NULL)
253 return (ESRCH);
254 if (!(cp == p ||
255 pc->pc_ucred->cr_uid == 0 ||
256 pc->p_ruid == p->p_cred->p_ruid ||
257 pc->pc_ucred->cr_uid == p->p_cred->p_ruid ||
258 pc->p_ruid == p->p_ucred->cr_uid ||
259 pc->pc_ucred->cr_uid == p->p_ucred->cr_uid))
260 return (EPERM);
261 }
262
263 /*
264 * We can't emulate anything but the default scheduling policy.
265 */
266 *retval = LINUX_SCHED_OTHER;
267 return (0);
268 }
269
270 int
271 linux_sys_sched_yield(cp, v, retval)
272 struct proc *cp;
273 void *v;
274 register_t *retval;
275 {
276 need_resched(curcpu());
277 return (0);
278 }
279
280 int
281 linux_sys_sched_get_priority_max(cp, v, retval)
282 struct proc *cp;
283 void *v;
284 register_t *retval;
285 {
286 struct linux_sys_sched_get_priority_max_args /* {
287 syscallarg(int) policy;
288 } */ *uap = v;
289
290 /*
291 * We can't emulate anything but the default scheduling policy.
292 */
293 if (SCARG(uap, policy) != LINUX_SCHED_OTHER) {
294 *retval = -1;
295 return (EINVAL);
296 }
297
298 *retval = 0;
299 return (0);
300 }
301
302 int
303 linux_sys_sched_get_priority_min(cp, v, retval)
304 struct proc *cp;
305 void *v;
306 register_t *retval;
307 {
308 struct linux_sys_sched_get_priority_min_args /* {
309 syscallarg(int) policy;
310 } */ *uap = v;
311
312 /*
313 * We can't emulate anything but the default scheduling policy.
314 */
315 if (SCARG(uap, policy) != LINUX_SCHED_OTHER) {
316 *retval = -1;
317 return (EINVAL);
318 }
319
320 *retval = 0;
321 return (0);
322 }