160727d8bSWarner Losh /*- 2*df57947fSPedro F. Giffuni * SPDX-License-Identifier: BSD-4-Clause 3*df57947fSPedro 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> 39f4636c59SDavid E. O'Brien __FBSDID("$FreeBSD$"); 40f4636c59SDavid E. O'Brien 41b565fb9eSAlfred Perlstein #include "opt_posix.h" 42b565fb9eSAlfred Perlstein 438a6472b7SPeter Dufault #include <sys/param.h> 448a6472b7SPeter Dufault #include <sys/systm.h> 458a6472b7SPeter Dufault #include <sys/kernel.h> 46fb919e4dSMark Murray #include <sys/lock.h> 478a6472b7SPeter Dufault #include <sys/module.h> 48fb919e4dSMark Murray #include <sys/mutex.h> 49acd3428bSRobert Watson #include <sys/priv.h> 50fb919e4dSMark Murray #include <sys/proc.h> 51bdd04ab1STom Rhodes #include <sys/posix4.h> 52fe24ab5fSJohn Baldwin #include <sys/syscallsubr.h> 538a6472b7SPeter Dufault #include <sys/sysctl.h> 54fb919e4dSMark Murray #include <sys/sysent.h> 55fb919e4dSMark Murray #include <sys/syslog.h> 56fb919e4dSMark Murray #include <sys/sysproto.h> 578a6472b7SPeter Dufault 588a6472b7SPeter Dufault MALLOC_DEFINE(M_P31B, "p1003.1b", "Posix 1003.1B"); 598a6472b7SPeter Dufault 60873fbcd7SRobert Watson /* The system calls return ENOSYS if an entry is called that is not run-time 61873fbcd7SRobert Watson * supported. I am also logging since some programs start to use this when 62873fbcd7SRobert Watson * they shouldn't. That will be removed if annoying. 632a61a110SPeter Dufault */ 648a6472b7SPeter Dufault int 65b40ce416SJulian Elischer syscall_not_present(struct thread *td, const char *s, struct nosys_args *uap) 668a6472b7SPeter Dufault { 678a6472b7SPeter Dufault log(LOG_ERR, "cmd %s pid %d tried to use non-present %s\n", 68431f8906SJulian Elischer td->td_name, td->td_proc->p_pid, s); 692a61a110SPeter Dufault 702a61a110SPeter Dufault /* a " return nosys(p, uap); " here causes a core dump. 712a61a110SPeter Dufault */ 722a61a110SPeter Dufault 732a61a110SPeter Dufault return ENOSYS; 748a6472b7SPeter Dufault } 758a6472b7SPeter Dufault 768a6472b7SPeter Dufault #if !defined(_KPOSIX_PRIORITY_SCHEDULING) 778a6472b7SPeter Dufault 78e9189611SPeter Wemm /* Not configured but loadable via a module: 798a6472b7SPeter Dufault */ 808a6472b7SPeter Dufault 81f6c040a2SDavid Xu static int 82f6c040a2SDavid Xu sched_attach(void) 838a6472b7SPeter Dufault { 848a6472b7SPeter Dufault return 0; 858a6472b7SPeter Dufault } 868a6472b7SPeter Dufault 878a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_setparam) 888a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_getparam) 898a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_setscheduler) 908a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_getscheduler) 918a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_yield) 928a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_get_priority_max) 938a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_get_priority_min) 948a6472b7SPeter Dufault SYSCALL_NOT_PRESENT_GEN(sched_rr_get_interval) 958a6472b7SPeter Dufault #else 968a6472b7SPeter Dufault 978a6472b7SPeter Dufault /* Configured in kernel version: 988a6472b7SPeter Dufault */ 998a6472b7SPeter Dufault static struct ksched *ksched; 1008a6472b7SPeter Dufault 101f6c040a2SDavid Xu static int 102f6c040a2SDavid Xu sched_attach(void) 1038a6472b7SPeter Dufault { 1048a6472b7SPeter Dufault int ret = ksched_attach(&ksched); 1058a6472b7SPeter Dufault 1068a6472b7SPeter Dufault if (ret == 0) 10734c1c599SJohn Baldwin p31b_setcfg(CTL_P1003_1B_PRIORITY_SCHEDULING, 200112L); 1088a6472b7SPeter Dufault 1098a6472b7SPeter Dufault return ret; 1108a6472b7SPeter Dufault } 1118a6472b7SPeter Dufault 112f6c040a2SDavid Xu int 1138451d0ddSKip Macy sys_sched_setparam(struct thread *td, struct sched_setparam_args *uap) 1148a6472b7SPeter Dufault { 115b40ce416SJulian Elischer struct thread *targettd; 1161af55356SRobert Watson struct proc *targetp; 1178a6472b7SPeter Dufault int e; 118aebde782SPeter Dufault struct sched_param sched_param; 1192afac34dSMatthew Dillon 120e8f7a952SRobert Watson e = copyin(uap->param, &sched_param, sizeof(sched_param)); 121e8f7a952SRobert Watson if (e) 122e8f7a952SRobert Watson return (e); 123aebde782SPeter Dufault 124e84b7987SRobert Watson if (uap->pid == 0) { 125b40ce416SJulian Elischer targetp = td->td_proc; 126b40ce416SJulian Elischer targettd = td; 127e84b7987SRobert Watson PROC_LOCK(targetp); 12824af5900SDavid Xu } else { 129e84b7987SRobert Watson targetp = pfind(uap->pid); 13065343c78SDavid Xu if (targetp == NULL) 13165343c78SDavid Xu return (ESRCH); 13265343c78SDavid Xu targettd = FIRST_THREAD_IN_PROC(targetp); 133e84b7987SRobert Watson } 134e84b7987SRobert Watson 135a93e83c8SDmitry Chagin e = kern_sched_setparam(td, targettd, &sched_param); 136e631cff3SDavid Xu PROC_UNLOCK(targetp); 13764e55bf4SRobert Watson return (e); 1388a6472b7SPeter Dufault } 1398a6472b7SPeter Dufault 140f6c040a2SDavid Xu int 141a93e83c8SDmitry Chagin kern_sched_setparam(struct thread *td, struct thread *targettd, 142a93e83c8SDmitry Chagin struct sched_param *param) 143a93e83c8SDmitry Chagin { 144a93e83c8SDmitry Chagin struct proc *targetp; 145a93e83c8SDmitry Chagin int error; 146a93e83c8SDmitry Chagin 147a93e83c8SDmitry Chagin targetp = targettd->td_proc; 148a93e83c8SDmitry Chagin PROC_LOCK_ASSERT(targetp, MA_OWNED); 149a93e83c8SDmitry Chagin 150a93e83c8SDmitry Chagin error = p_cansched(td, targetp); 151a93e83c8SDmitry Chagin if (error == 0) 152a93e83c8SDmitry Chagin error = ksched_setparam(ksched, targettd, 153a93e83c8SDmitry Chagin (const struct sched_param *)param); 154a93e83c8SDmitry Chagin return (error); 155a93e83c8SDmitry Chagin } 156a93e83c8SDmitry Chagin 157a93e83c8SDmitry Chagin int 1588451d0ddSKip Macy sys_sched_getparam(struct thread *td, struct sched_getparam_args *uap) 1598a6472b7SPeter Dufault { 1608a6472b7SPeter Dufault int e; 161aebde782SPeter Dufault struct sched_param sched_param; 162b40ce416SJulian Elischer struct thread *targettd; 1631af55356SRobert Watson struct proc *targetp; 1648a6472b7SPeter Dufault 165e84b7987SRobert Watson if (uap->pid == 0) { 166b40ce416SJulian Elischer targetp = td->td_proc; 167b40ce416SJulian Elischer targettd = td; 168e84b7987SRobert Watson PROC_LOCK(targetp); 16924af5900SDavid Xu } else { 170e84b7987SRobert Watson targetp = pfind(uap->pid); 1712afac34dSMatthew Dillon if (targetp == NULL) { 17265343c78SDavid Xu return (ESRCH); 1732afac34dSMatthew Dillon } 1746617724cSJeff Roberson targettd = FIRST_THREAD_IN_PROC(targetp); 175e84b7987SRobert Watson } 176e84b7987SRobert Watson 177a93e83c8SDmitry Chagin e = kern_sched_getparam(td, targettd, &sched_param); 178e84b7987SRobert Watson PROC_UNLOCK(targetp); 1792afac34dSMatthew Dillon if (e == 0) 18064e55bf4SRobert Watson e = copyout(&sched_param, uap->param, sizeof(sched_param)); 18164e55bf4SRobert Watson return (e); 1828a6472b7SPeter Dufault } 183b40ce416SJulian Elischer 184f6c040a2SDavid Xu int 185a93e83c8SDmitry Chagin kern_sched_getparam(struct thread *td, struct thread *targettd, 186a93e83c8SDmitry Chagin struct sched_param *param) 187a93e83c8SDmitry Chagin { 188a93e83c8SDmitry Chagin struct proc *targetp; 189a93e83c8SDmitry Chagin int error; 190a93e83c8SDmitry Chagin 191a93e83c8SDmitry Chagin targetp = targettd->td_proc; 192a93e83c8SDmitry Chagin PROC_LOCK_ASSERT(targetp, MA_OWNED); 193a93e83c8SDmitry Chagin 194a93e83c8SDmitry Chagin error = p_cansee(td, targetp); 195a93e83c8SDmitry Chagin if (error == 0) 196a93e83c8SDmitry Chagin error = ksched_getparam(ksched, targettd, param); 197a93e83c8SDmitry Chagin return (error); 198a93e83c8SDmitry Chagin } 199a93e83c8SDmitry Chagin 200a93e83c8SDmitry Chagin int 2018451d0ddSKip Macy sys_sched_setscheduler(struct thread *td, struct sched_setscheduler_args *uap) 2028a6472b7SPeter Dufault { 2038a6472b7SPeter Dufault int e; 204aebde782SPeter Dufault struct sched_param sched_param; 205b40ce416SJulian Elischer struct thread *targettd; 2061af55356SRobert Watson struct proc *targetp; 2071af55356SRobert Watson 208e8f7a952SRobert Watson e = copyin(uap->param, &sched_param, sizeof(sched_param)); 209e8f7a952SRobert Watson if (e) 210e8f7a952SRobert Watson return (e); 211aebde782SPeter Dufault 212e84b7987SRobert Watson if (uap->pid == 0) { 213b40ce416SJulian Elischer targetp = td->td_proc; 214b40ce416SJulian Elischer targettd = td; 215e84b7987SRobert Watson PROC_LOCK(targetp); 21624af5900SDavid Xu } else { 217e84b7987SRobert Watson targetp = pfind(uap->pid); 21865343c78SDavid Xu if (targetp == NULL) 21965343c78SDavid Xu return (ESRCH); 22065343c78SDavid Xu targettd = FIRST_THREAD_IN_PROC(targetp); 221e84b7987SRobert Watson } 222e84b7987SRobert Watson 223a93e83c8SDmitry Chagin e = kern_sched_setscheduler(td, targettd, uap->policy, 224a93e83c8SDmitry Chagin &sched_param); 225e631cff3SDavid Xu PROC_UNLOCK(targetp); 22664e55bf4SRobert Watson return (e); 2278a6472b7SPeter Dufault } 228b40ce416SJulian Elischer 229f6c040a2SDavid Xu int 230a93e83c8SDmitry Chagin kern_sched_setscheduler(struct thread *td, struct thread *targettd, 231a93e83c8SDmitry Chagin int policy, struct sched_param *param) 232a93e83c8SDmitry Chagin { 233a93e83c8SDmitry Chagin struct proc *targetp; 234a93e83c8SDmitry Chagin int error; 235a93e83c8SDmitry Chagin 236a93e83c8SDmitry Chagin targetp = targettd->td_proc; 237a93e83c8SDmitry Chagin PROC_LOCK_ASSERT(targetp, MA_OWNED); 238a93e83c8SDmitry Chagin 239a93e83c8SDmitry Chagin /* Don't allow non root user to set a scheduler policy. */ 240a93e83c8SDmitry Chagin error = priv_check(td, PRIV_SCHED_SET); 241a93e83c8SDmitry Chagin if (error) 242a93e83c8SDmitry Chagin return (error); 243a93e83c8SDmitry Chagin 244a93e83c8SDmitry Chagin error = p_cansched(td, targetp); 245a93e83c8SDmitry Chagin if (error == 0) 246a93e83c8SDmitry Chagin error = ksched_setscheduler(ksched, targettd, policy, 247a93e83c8SDmitry Chagin (const struct sched_param *)param); 248a93e83c8SDmitry Chagin return (error); 249a93e83c8SDmitry Chagin } 250a93e83c8SDmitry Chagin 251a93e83c8SDmitry Chagin int 2528451d0ddSKip Macy sys_sched_getscheduler(struct thread *td, struct sched_getscheduler_args *uap) 2538a6472b7SPeter Dufault { 25465343c78SDavid Xu int e, policy; 255b40ce416SJulian Elischer struct thread *targettd; 2561af55356SRobert Watson struct proc *targetp; 2578a6472b7SPeter Dufault 258e84b7987SRobert Watson if (uap->pid == 0) { 259b40ce416SJulian Elischer targetp = td->td_proc; 260b40ce416SJulian Elischer targettd = td; 261e84b7987SRobert Watson PROC_LOCK(targetp); 26224af5900SDavid Xu } else { 263e84b7987SRobert Watson targetp = pfind(uap->pid); 264931e4573SDavid Xu if (targetp == NULL) 265931e4573SDavid Xu return (ESRCH); 2666617724cSJeff Roberson targettd = FIRST_THREAD_IN_PROC(targetp); 267e84b7987SRobert Watson } 268e84b7987SRobert Watson 269a93e83c8SDmitry Chagin e = kern_sched_getscheduler(td, targettd, &policy); 270e631cff3SDavid Xu PROC_UNLOCK(targetp); 271a93e83c8SDmitry Chagin if (e == 0) 272a93e83c8SDmitry Chagin td->td_retval[0] = policy; 27364e55bf4SRobert Watson 27464e55bf4SRobert Watson return (e); 2758a6472b7SPeter Dufault } 276b40ce416SJulian Elischer 277f6c040a2SDavid Xu int 278a93e83c8SDmitry Chagin kern_sched_getscheduler(struct thread *td, struct thread *targettd, 279a93e83c8SDmitry Chagin int *policy) 280a93e83c8SDmitry Chagin { 281a93e83c8SDmitry Chagin struct proc *targetp; 282a93e83c8SDmitry Chagin int error; 283a93e83c8SDmitry Chagin 284a93e83c8SDmitry Chagin targetp = targettd->td_proc; 285a93e83c8SDmitry Chagin PROC_LOCK_ASSERT(targetp, MA_OWNED); 286a93e83c8SDmitry Chagin 287a93e83c8SDmitry Chagin error = p_cansee(td, targetp); 288a93e83c8SDmitry Chagin if (error == 0) 289a93e83c8SDmitry Chagin error = ksched_getscheduler(ksched, targettd, policy); 290a93e83c8SDmitry Chagin return (error); 291a93e83c8SDmitry Chagin } 292a93e83c8SDmitry Chagin 293a93e83c8SDmitry Chagin int 2948451d0ddSKip Macy sys_sched_yield(struct thread *td, struct sched_yield_args *uap) 2958a6472b7SPeter Dufault { 2962afac34dSMatthew Dillon 297fe7979a1SMateusz Guzik sched_relinquish(td); 298fe7979a1SMateusz Guzik return (0); 2998a6472b7SPeter Dufault } 300b40ce416SJulian Elischer 301f6c040a2SDavid Xu int 3028451d0ddSKip Macy sys_sched_get_priority_max(struct thread *td, 3038a6472b7SPeter Dufault struct sched_get_priority_max_args *uap) 3048a6472b7SPeter Dufault { 30565343c78SDavid Xu int error, prio; 3062afac34dSMatthew Dillon 30765343c78SDavid Xu error = ksched_get_priority_max(ksched, uap->policy, &prio); 30865343c78SDavid Xu td->td_retval[0] = prio; 3092afac34dSMatthew Dillon return (error); 3108a6472b7SPeter Dufault } 311b40ce416SJulian Elischer 312f6c040a2SDavid Xu int 3138451d0ddSKip Macy sys_sched_get_priority_min(struct thread *td, 3148a6472b7SPeter Dufault struct sched_get_priority_min_args *uap) 3158a6472b7SPeter Dufault { 31665343c78SDavid Xu int error, prio; 317b40ce416SJulian Elischer 31865343c78SDavid Xu error = ksched_get_priority_min(ksched, uap->policy, &prio); 31965343c78SDavid Xu td->td_retval[0] = prio; 3202afac34dSMatthew Dillon return (error); 3218a6472b7SPeter Dufault } 322b40ce416SJulian Elischer 323f6c040a2SDavid Xu int 3248451d0ddSKip Macy sys_sched_rr_get_interval(struct thread *td, 3258a6472b7SPeter Dufault struct sched_rr_get_interval_args *uap) 3268a6472b7SPeter Dufault { 327fe24ab5fSJohn Baldwin struct timespec timespec; 328fe24ab5fSJohn Baldwin int error; 329fe24ab5fSJohn Baldwin 330fe24ab5fSJohn Baldwin error = kern_sched_rr_get_interval(td, uap->pid, ×pec); 331fe24ab5fSJohn Baldwin if (error == 0) 332fe24ab5fSJohn Baldwin error = copyout(×pec, uap->interval, sizeof(timespec)); 333fe24ab5fSJohn Baldwin return (error); 334fe24ab5fSJohn Baldwin } 335fe24ab5fSJohn Baldwin 336f6c040a2SDavid Xu int 337f6c040a2SDavid Xu kern_sched_rr_get_interval(struct thread *td, pid_t pid, 338fe24ab5fSJohn Baldwin struct timespec *ts) 339fe24ab5fSJohn Baldwin { 3408a6472b7SPeter Dufault int e; 341b40ce416SJulian Elischer struct thread *targettd; 3421af55356SRobert Watson struct proc *targetp; 3438a6472b7SPeter Dufault 344fe24ab5fSJohn Baldwin if (pid == 0) { 345b40ce416SJulian Elischer targettd = td; 346b40ce416SJulian Elischer targetp = td->td_proc; 347e84b7987SRobert Watson PROC_LOCK(targetp); 34865343c78SDavid Xu } else { 349931e4573SDavid Xu targetp = pfind(pid); 350931e4573SDavid Xu if (targetp == NULL) 35165343c78SDavid Xu return (ESRCH); 352931e4573SDavid Xu targettd = FIRST_THREAD_IN_PROC(targetp); 353e84b7987SRobert Watson } 354e84b7987SRobert Watson 3551aa90ecaSDmitry Chagin e = kern_sched_rr_get_interval_td(td, targettd, ts); 356fe24ab5fSJohn Baldwin PROC_UNLOCK(targetp); 35764e55bf4SRobert Watson return (e); 3588a6472b7SPeter Dufault } 3598a6472b7SPeter Dufault 3601aa90ecaSDmitry Chagin int 3611aa90ecaSDmitry Chagin kern_sched_rr_get_interval_td(struct thread *td, struct thread *targettd, 3621aa90ecaSDmitry Chagin struct timespec *ts) 3631aa90ecaSDmitry Chagin { 3641aa90ecaSDmitry Chagin struct proc *p; 3651aa90ecaSDmitry Chagin int error; 3661aa90ecaSDmitry Chagin 3671aa90ecaSDmitry Chagin p = targettd->td_proc; 3681aa90ecaSDmitry Chagin PROC_LOCK_ASSERT(p, MA_OWNED); 3691aa90ecaSDmitry Chagin 3701aa90ecaSDmitry Chagin error = p_cansee(td, p); 3711aa90ecaSDmitry Chagin if (error == 0) 3721aa90ecaSDmitry Chagin error = ksched_rr_get_interval(ksched, targettd, ts); 3731aa90ecaSDmitry Chagin return (error); 3741aa90ecaSDmitry Chagin } 3758a6472b7SPeter Dufault #endif 3768a6472b7SPeter Dufault 377f6c040a2SDavid Xu static void 378f6c040a2SDavid Xu p31binit(void *notused) 3798a6472b7SPeter Dufault { 3808a6472b7SPeter Dufault (void) sched_attach(); 381ce47711dSPeter Dufault p31b_setcfg(CTL_P1003_1B_PAGESIZE, PAGE_SIZE); 3828a6472b7SPeter Dufault } 3838a6472b7SPeter Dufault 3848a6472b7SPeter Dufault SYSINIT(p31b, SI_SUB_P1003_1B, SI_ORDER_FIRST, p31binit, NULL); 385