160727d8bSWarner Losh /*-
2df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause
3df57947fSPedro F. Giffuni *
48a6472b7SPeter Dufault * Copyright (c) 1996, 1997, 1998
58a6472b7SPeter Dufault * HD Associates, Inc. All rights reserved.
68a6472b7SPeter Dufault *
78a6472b7SPeter Dufault * Redistribution and use in source and binary forms, with or without
88a6472b7SPeter Dufault * modification, are permitted provided that the following conditions
98a6472b7SPeter Dufault * are met:
108a6472b7SPeter Dufault * 1. Redistributions of source code must retain the above copyright
118a6472b7SPeter Dufault * notice, this list of conditions and the following disclaimer.
128a6472b7SPeter Dufault * 2. Redistributions in binary form must reproduce the above copyright
138a6472b7SPeter Dufault * notice, this list of conditions and the following disclaimer in the
148a6472b7SPeter Dufault * documentation and/or other materials provided with the distribution.
158a6472b7SPeter Dufault * 3. All advertising materials mentioning features or use of this software
168a6472b7SPeter Dufault * must display the following acknowledgement:
178a6472b7SPeter Dufault * This product includes software developed by HD Associates, Inc
188a6472b7SPeter Dufault * 4. Neither the name of the author nor the names of any co-contributors
198a6472b7SPeter Dufault * may be used to endorse or promote products derived from this software
208a6472b7SPeter Dufault * without specific prior written permission.
218a6472b7SPeter Dufault *
228a6472b7SPeter Dufault * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND
238a6472b7SPeter Dufault * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
248a6472b7SPeter Dufault * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
258a6472b7SPeter Dufault * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE
268a6472b7SPeter Dufault * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
278a6472b7SPeter Dufault * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
288a6472b7SPeter Dufault * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
298a6472b7SPeter Dufault * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
308a6472b7SPeter Dufault * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
318a6472b7SPeter Dufault * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
328a6472b7SPeter Dufault * SUCH DAMAGE.
338a6472b7SPeter Dufault */
348a6472b7SPeter Dufault
358a6472b7SPeter Dufault /* p1003_1b: Real Time common code.
368a6472b7SPeter Dufault */
378a6472b7SPeter Dufault
38f4636c59SDavid E. O'Brien #include <sys/cdefs.h>
39b565fb9eSAlfred Perlstein #include "opt_posix.h"
40b565fb9eSAlfred Perlstein
418a6472b7SPeter Dufault #include <sys/param.h>
428a6472b7SPeter Dufault #include <sys/systm.h>
438a6472b7SPeter Dufault #include <sys/kernel.h>
44fb919e4dSMark Murray #include <sys/lock.h>
458a6472b7SPeter Dufault #include <sys/module.h>
46fb919e4dSMark Murray #include <sys/mutex.h>
47acd3428bSRobert Watson #include <sys/priv.h>
48fb919e4dSMark Murray #include <sys/proc.h>
49bdd04ab1STom Rhodes #include <sys/posix4.h>
50fe24ab5fSJohn Baldwin #include <sys/syscallsubr.h>
518a6472b7SPeter Dufault #include <sys/sysctl.h>
52fb919e4dSMark Murray #include <sys/syslog.h>
53fb919e4dSMark Murray #include <sys/sysproto.h>
548a6472b7SPeter Dufault
558a6472b7SPeter Dufault MALLOC_DEFINE(M_P31B, "p1003.1b", "Posix 1003.1B");
568a6472b7SPeter Dufault
57873fbcd7SRobert Watson /* The system calls return ENOSYS if an entry is called that is not run-time
58873fbcd7SRobert Watson * supported. I am also logging since some programs start to use this when
59873fbcd7SRobert Watson * they shouldn't. That will be removed if annoying.
602a61a110SPeter Dufault */
618a6472b7SPeter Dufault int
syscall_not_present(struct thread * td,const char * s,struct nosys_args * uap)62b40ce416SJulian Elischer syscall_not_present(struct thread *td, const char *s, struct nosys_args *uap)
638a6472b7SPeter Dufault {
648a6472b7SPeter Dufault log(LOG_ERR, "cmd %s pid %d tried to use non-present %s\n",
65431f8906SJulian Elischer td->td_name, td->td_proc->p_pid, s);
662a61a110SPeter Dufault
672a61a110SPeter Dufault /* a " return nosys(p, uap); " here causes a core dump.
682a61a110SPeter Dufault */
692a61a110SPeter Dufault
702a61a110SPeter Dufault return ENOSYS;
718a6472b7SPeter Dufault }
728a6472b7SPeter Dufault
738a6472b7SPeter Dufault #if !defined(_KPOSIX_PRIORITY_SCHEDULING)
748a6472b7SPeter Dufault
75e9189611SPeter Wemm /* Not configured but loadable via a module:
768a6472b7SPeter Dufault */
778a6472b7SPeter Dufault
78f6c040a2SDavid Xu static int
sched_attach(void)79f6c040a2SDavid Xu sched_attach(void)
808a6472b7SPeter Dufault {
818a6472b7SPeter Dufault return 0;
828a6472b7SPeter Dufault }
838a6472b7SPeter Dufault
848a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_setparam)
SYSCALL_NOT_PRESENT_GEN(sched_getparam)858a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_getparam)
868a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_setscheduler)
878a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_getscheduler)
888a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_yield)
898a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_get_priority_max)
908a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_get_priority_min)
918a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_rr_get_interval)
928a6472b7SPeter Dufault #else
938a6472b7SPeter Dufault
948a6472b7SPeter Dufault /* Configured in kernel version:
958a6472b7SPeter Dufault */
968a6472b7SPeter Dufault static struct ksched *ksched;
978a6472b7SPeter Dufault
98f6c040a2SDavid Xu static int
99f6c040a2SDavid Xu sched_attach(void)
1008a6472b7SPeter Dufault {
1018a6472b7SPeter Dufault int ret = ksched_attach(&ksched);
1028a6472b7SPeter Dufault
1038a6472b7SPeter Dufault if (ret == 0)
10434c1c599SJohn Baldwin p31b_setcfg(CTL_P1003_1B_PRIORITY_SCHEDULING, 200112L);
1058a6472b7SPeter Dufault
1068a6472b7SPeter Dufault return ret;
1078a6472b7SPeter Dufault }
1088a6472b7SPeter Dufault
109f6c040a2SDavid Xu int
1108451d0ddSKip Macy sys_sched_setparam(struct thread *td, struct sched_setparam_args *uap)
1118a6472b7SPeter Dufault {
112b40ce416SJulian Elischer struct thread *targettd;
1131af55356SRobert Watson struct proc *targetp;
1148a6472b7SPeter Dufault int e;
115aebde782SPeter Dufault struct sched_param sched_param;
1162afac34dSMatthew Dillon
117e8f7a952SRobert Watson e = copyin(uap->param, &sched_param, sizeof(sched_param));
118e8f7a952SRobert Watson if (e)
119e8f7a952SRobert Watson return (e);
120aebde782SPeter Dufault
121e84b7987SRobert Watson if (uap->pid == 0) {
122b40ce416SJulian Elischer targetp = td->td_proc;
123b40ce416SJulian Elischer targettd = td;
124e84b7987SRobert Watson PROC_LOCK(targetp);
12524af5900SDavid Xu } else {
126e84b7987SRobert Watson targetp = pfind(uap->pid);
12765343c78SDavid Xu if (targetp == NULL)
12865343c78SDavid Xu return (ESRCH);
12965343c78SDavid Xu targettd = FIRST_THREAD_IN_PROC(targetp);
130e84b7987SRobert Watson }
131e84b7987SRobert Watson
132a93e83c8SDmitry Chagin e = kern_sched_setparam(td, targettd, &sched_param);
133e631cff3SDavid Xu PROC_UNLOCK(targetp);
13464e55bf4SRobert Watson return (e);
1358a6472b7SPeter Dufault }
1368a6472b7SPeter Dufault
137f6c040a2SDavid Xu int
138a93e83c8SDmitry Chagin kern_sched_setparam(struct thread *td, struct thread *targettd,
139a93e83c8SDmitry Chagin struct sched_param *param)
140a93e83c8SDmitry Chagin {
141a93e83c8SDmitry Chagin struct proc *targetp;
142a93e83c8SDmitry Chagin int error;
143a93e83c8SDmitry Chagin
144a93e83c8SDmitry Chagin targetp = targettd->td_proc;
145a93e83c8SDmitry Chagin PROC_LOCK_ASSERT(targetp, MA_OWNED);
146a93e83c8SDmitry Chagin
147a93e83c8SDmitry Chagin error = p_cansched(td, targetp);
148a93e83c8SDmitry Chagin if (error == 0)
149a93e83c8SDmitry Chagin error = ksched_setparam(ksched, targettd,
150a93e83c8SDmitry Chagin (const struct sched_param *)param);
151a93e83c8SDmitry Chagin return (error);
152a93e83c8SDmitry Chagin }
153a93e83c8SDmitry Chagin
154a93e83c8SDmitry Chagin int
1558451d0ddSKip Macy sys_sched_getparam(struct thread *td, struct sched_getparam_args *uap)
1568a6472b7SPeter Dufault {
1578a6472b7SPeter Dufault int e;
158aebde782SPeter Dufault struct sched_param sched_param;
159b40ce416SJulian Elischer struct thread *targettd;
1601af55356SRobert Watson struct proc *targetp;
1618a6472b7SPeter Dufault
162e84b7987SRobert Watson if (uap->pid == 0) {
163b40ce416SJulian Elischer targetp = td->td_proc;
164b40ce416SJulian Elischer targettd = td;
165e84b7987SRobert Watson PROC_LOCK(targetp);
16624af5900SDavid Xu } else {
167e84b7987SRobert Watson targetp = pfind(uap->pid);
1682afac34dSMatthew Dillon if (targetp == NULL) {
16965343c78SDavid Xu return (ESRCH);
1702afac34dSMatthew Dillon }
1716617724cSJeff Roberson targettd = FIRST_THREAD_IN_PROC(targetp);
172e84b7987SRobert Watson }
173e84b7987SRobert Watson
174a93e83c8SDmitry Chagin e = kern_sched_getparam(td, targettd, &sched_param);
175e84b7987SRobert Watson PROC_UNLOCK(targetp);
1762afac34dSMatthew Dillon if (e == 0)
17764e55bf4SRobert Watson e = copyout(&sched_param, uap->param, sizeof(sched_param));
17864e55bf4SRobert Watson return (e);
1798a6472b7SPeter Dufault }
180b40ce416SJulian Elischer
181f6c040a2SDavid Xu int
182a93e83c8SDmitry Chagin kern_sched_getparam(struct thread *td, struct thread *targettd,
183a93e83c8SDmitry Chagin struct sched_param *param)
184a93e83c8SDmitry Chagin {
185a93e83c8SDmitry Chagin struct proc *targetp;
186a93e83c8SDmitry Chagin int error;
187a93e83c8SDmitry Chagin
188a93e83c8SDmitry Chagin targetp = targettd->td_proc;
189a93e83c8SDmitry Chagin PROC_LOCK_ASSERT(targetp, MA_OWNED);
190a93e83c8SDmitry Chagin
191a93e83c8SDmitry Chagin error = p_cansee(td, targetp);
192a93e83c8SDmitry Chagin if (error == 0)
193a93e83c8SDmitry Chagin error = ksched_getparam(ksched, targettd, param);
194a93e83c8SDmitry Chagin return (error);
195a93e83c8SDmitry Chagin }
196a93e83c8SDmitry Chagin
197a93e83c8SDmitry Chagin int
1988451d0ddSKip Macy sys_sched_setscheduler(struct thread *td, struct sched_setscheduler_args *uap)
1998a6472b7SPeter Dufault {
2008a6472b7SPeter Dufault int e;
201aebde782SPeter Dufault struct sched_param sched_param;
202b40ce416SJulian Elischer struct thread *targettd;
2031af55356SRobert Watson struct proc *targetp;
2041af55356SRobert Watson
205e8f7a952SRobert Watson e = copyin(uap->param, &sched_param, sizeof(sched_param));
206e8f7a952SRobert Watson if (e)
207e8f7a952SRobert Watson return (e);
208aebde782SPeter Dufault
209e84b7987SRobert Watson if (uap->pid == 0) {
210b40ce416SJulian Elischer targetp = td->td_proc;
211b40ce416SJulian Elischer targettd = td;
212e84b7987SRobert Watson PROC_LOCK(targetp);
21324af5900SDavid Xu } else {
214e84b7987SRobert Watson targetp = pfind(uap->pid);
21565343c78SDavid Xu if (targetp == NULL)
21665343c78SDavid Xu return (ESRCH);
21765343c78SDavid Xu targettd = FIRST_THREAD_IN_PROC(targetp);
218e84b7987SRobert Watson }
219e84b7987SRobert Watson
220a93e83c8SDmitry Chagin e = kern_sched_setscheduler(td, targettd, uap->policy,
221a93e83c8SDmitry Chagin &sched_param);
222e631cff3SDavid Xu PROC_UNLOCK(targetp);
22364e55bf4SRobert Watson return (e);
2248a6472b7SPeter Dufault }
225b40ce416SJulian Elischer
226f6c040a2SDavid Xu int
227a93e83c8SDmitry Chagin kern_sched_setscheduler(struct thread *td, struct thread *targettd,
228a93e83c8SDmitry Chagin int policy, struct sched_param *param)
229a93e83c8SDmitry Chagin {
230a93e83c8SDmitry Chagin struct proc *targetp;
231a93e83c8SDmitry Chagin int error;
232a93e83c8SDmitry Chagin
233a93e83c8SDmitry Chagin targetp = targettd->td_proc;
234a93e83c8SDmitry Chagin PROC_LOCK_ASSERT(targetp, MA_OWNED);
235a93e83c8SDmitry Chagin
236*2198221bSFlorian Walpen /* Only privileged users are allowed to set a scheduler policy. */
237*2198221bSFlorian Walpen error = priv_check(td, PRIV_SCHED_SETPOLICY);
238a93e83c8SDmitry Chagin if (error)
239a93e83c8SDmitry Chagin return (error);
240a93e83c8SDmitry Chagin
241a93e83c8SDmitry Chagin error = p_cansched(td, targetp);
242a93e83c8SDmitry Chagin if (error == 0)
243a93e83c8SDmitry Chagin error = ksched_setscheduler(ksched, targettd, policy,
244a93e83c8SDmitry Chagin (const struct sched_param *)param);
245a93e83c8SDmitry Chagin return (error);
246a93e83c8SDmitry Chagin }
247a93e83c8SDmitry Chagin
248a93e83c8SDmitry Chagin int
2498451d0ddSKip Macy sys_sched_getscheduler(struct thread *td, struct sched_getscheduler_args *uap)
2508a6472b7SPeter Dufault {
25165343c78SDavid Xu int e, policy;
252b40ce416SJulian Elischer struct thread *targettd;
2531af55356SRobert Watson struct proc *targetp;
2548a6472b7SPeter Dufault
255e84b7987SRobert Watson if (uap->pid == 0) {
256b40ce416SJulian Elischer targetp = td->td_proc;
257b40ce416SJulian Elischer targettd = td;
258e84b7987SRobert Watson PROC_LOCK(targetp);
25924af5900SDavid Xu } else {
260e84b7987SRobert Watson targetp = pfind(uap->pid);
261931e4573SDavid Xu if (targetp == NULL)
262931e4573SDavid Xu return (ESRCH);
2636617724cSJeff Roberson targettd = FIRST_THREAD_IN_PROC(targetp);
264e84b7987SRobert Watson }
265e84b7987SRobert Watson
266a93e83c8SDmitry Chagin e = kern_sched_getscheduler(td, targettd, &policy);
267e631cff3SDavid Xu PROC_UNLOCK(targetp);
268a93e83c8SDmitry Chagin if (e == 0)
269a93e83c8SDmitry Chagin td->td_retval[0] = policy;
27064e55bf4SRobert Watson
27164e55bf4SRobert Watson return (e);
2728a6472b7SPeter Dufault }
273b40ce416SJulian Elischer
274f6c040a2SDavid Xu int
275a93e83c8SDmitry Chagin kern_sched_getscheduler(struct thread *td, struct thread *targettd,
276a93e83c8SDmitry Chagin int *policy)
277a93e83c8SDmitry Chagin {
278a93e83c8SDmitry Chagin struct proc *targetp;
279a93e83c8SDmitry Chagin int error;
280a93e83c8SDmitry Chagin
281a93e83c8SDmitry Chagin targetp = targettd->td_proc;
282a93e83c8SDmitry Chagin PROC_LOCK_ASSERT(targetp, MA_OWNED);
283a93e83c8SDmitry Chagin
284a93e83c8SDmitry Chagin error = p_cansee(td, targetp);
285a93e83c8SDmitry Chagin if (error == 0)
286a93e83c8SDmitry Chagin error = ksched_getscheduler(ksched, targettd, policy);
287a93e83c8SDmitry Chagin return (error);
288a93e83c8SDmitry Chagin }
289a93e83c8SDmitry Chagin
290a93e83c8SDmitry Chagin int
2918451d0ddSKip Macy sys_sched_yield(struct thread *td, struct sched_yield_args *uap)
2928a6472b7SPeter Dufault {
2932afac34dSMatthew Dillon
294fe7979a1SMateusz Guzik sched_relinquish(td);
295fe7979a1SMateusz Guzik return (0);
2968a6472b7SPeter Dufault }
297b40ce416SJulian Elischer
298f6c040a2SDavid Xu int
2998451d0ddSKip Macy sys_sched_get_priority_max(struct thread *td,
3008a6472b7SPeter Dufault struct sched_get_priority_max_args *uap)
3018a6472b7SPeter Dufault {
30265343c78SDavid Xu int error, prio;
3032afac34dSMatthew Dillon
30465343c78SDavid Xu error = ksched_get_priority_max(ksched, uap->policy, &prio);
30565343c78SDavid Xu td->td_retval[0] = prio;
3062afac34dSMatthew Dillon return (error);
3078a6472b7SPeter Dufault }
308b40ce416SJulian Elischer
309f6c040a2SDavid Xu int
3108451d0ddSKip Macy sys_sched_get_priority_min(struct thread *td,
3118a6472b7SPeter Dufault struct sched_get_priority_min_args *uap)
3128a6472b7SPeter Dufault {
31365343c78SDavid Xu int error, prio;
314b40ce416SJulian Elischer
31565343c78SDavid Xu error = ksched_get_priority_min(ksched, uap->policy, &prio);
31665343c78SDavid Xu td->td_retval[0] = prio;
3172afac34dSMatthew Dillon return (error);
3188a6472b7SPeter Dufault }
319b40ce416SJulian Elischer
320f6c040a2SDavid Xu int
3218451d0ddSKip Macy sys_sched_rr_get_interval(struct thread *td,
3228a6472b7SPeter Dufault struct sched_rr_get_interval_args *uap)
3238a6472b7SPeter Dufault {
324fe24ab5fSJohn Baldwin struct timespec timespec;
325fe24ab5fSJohn Baldwin int error;
326fe24ab5fSJohn Baldwin
327fe24ab5fSJohn Baldwin error = kern_sched_rr_get_interval(td, uap->pid, ×pec);
328fe24ab5fSJohn Baldwin if (error == 0)
329fe24ab5fSJohn Baldwin error = copyout(×pec, uap->interval, sizeof(timespec));
330fe24ab5fSJohn Baldwin return (error);
331fe24ab5fSJohn Baldwin }
332fe24ab5fSJohn Baldwin
333f6c040a2SDavid Xu int
334f6c040a2SDavid Xu kern_sched_rr_get_interval(struct thread *td, pid_t pid,
335fe24ab5fSJohn Baldwin struct timespec *ts)
336fe24ab5fSJohn Baldwin {
3378a6472b7SPeter Dufault int e;
338b40ce416SJulian Elischer struct thread *targettd;
3391af55356SRobert Watson struct proc *targetp;
3408a6472b7SPeter Dufault
341fe24ab5fSJohn Baldwin if (pid == 0) {
342b40ce416SJulian Elischer targettd = td;
343b40ce416SJulian Elischer targetp = td->td_proc;
344e84b7987SRobert Watson PROC_LOCK(targetp);
34565343c78SDavid Xu } else {
346931e4573SDavid Xu targetp = pfind(pid);
347931e4573SDavid Xu if (targetp == NULL)
34865343c78SDavid Xu return (ESRCH);
349931e4573SDavid Xu targettd = FIRST_THREAD_IN_PROC(targetp);
350e84b7987SRobert Watson }
351e84b7987SRobert Watson
3521aa90ecaSDmitry Chagin e = kern_sched_rr_get_interval_td(td, targettd, ts);
353fe24ab5fSJohn Baldwin PROC_UNLOCK(targetp);
35464e55bf4SRobert Watson return (e);
3558a6472b7SPeter Dufault }
3568a6472b7SPeter Dufault
3571aa90ecaSDmitry Chagin int
3581aa90ecaSDmitry Chagin kern_sched_rr_get_interval_td(struct thread *td, struct thread *targettd,
3591aa90ecaSDmitry Chagin struct timespec *ts)
3601aa90ecaSDmitry Chagin {
3611aa90ecaSDmitry Chagin struct proc *p;
3621aa90ecaSDmitry Chagin int error;
3631aa90ecaSDmitry Chagin
3641aa90ecaSDmitry Chagin p = targettd->td_proc;
3651aa90ecaSDmitry Chagin PROC_LOCK_ASSERT(p, MA_OWNED);
3661aa90ecaSDmitry Chagin
3671aa90ecaSDmitry Chagin error = p_cansee(td, p);
3681aa90ecaSDmitry Chagin if (error == 0)
3691aa90ecaSDmitry Chagin error = ksched_rr_get_interval(ksched, targettd, ts);
3701aa90ecaSDmitry Chagin return (error);
3711aa90ecaSDmitry Chagin }
3728a6472b7SPeter Dufault #endif
3738a6472b7SPeter Dufault
374f6c040a2SDavid Xu static void
375f6c040a2SDavid Xu p31binit(void *notused)
3768a6472b7SPeter Dufault {
3778a6472b7SPeter Dufault (void) sched_attach();
378ce47711dSPeter Dufault p31b_setcfg(CTL_P1003_1B_PAGESIZE, PAGE_SIZE);
3798a6472b7SPeter Dufault }
3808a6472b7SPeter Dufault
3818a6472b7SPeter Dufault SYSINIT(p31b, SI_SUB_P1003_1B, SI_ORDER_FIRST, p31binit, NULL);
382