1 /*- 2 * SPDX-License-Identifier: BSD-4-Clause 3 * 4 * Copyright (c) 1996, 1997, 1998 5 * HD Associates, Inc. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by HD Associates, Inc 18 * 4. Neither the name of the author nor the names of any co-contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY HD ASSOCIATES AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL HD ASSOCIATES OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 /* p1003_1b: Real Time common code. 36 */ 37 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD$"); 40 41 #include "opt_posix.h" 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/kernel.h> 46 #include <sys/lock.h> 47 #include <sys/module.h> 48 #include <sys/mutex.h> 49 #include <sys/priv.h> 50 #include <sys/proc.h> 51 #include <sys/posix4.h> 52 #include <sys/syscallsubr.h> 53 #include <sys/sysctl.h> 54 #include <sys/syslog.h> 55 #include <sys/sysproto.h> 56 57 MALLOC_DEFINE(M_P31B, "p1003.1b", "Posix 1003.1B"); 58 59 /* The system calls return ENOSYS if an entry is called that is not run-time 60 * supported. I am also logging since some programs start to use this when 61 * they shouldn't. That will be removed if annoying. 62 */ 63 int 64 syscall_not_present(struct thread *td, const char *s, struct nosys_args *uap) 65 { 66 log(LOG_ERR, "cmd %s pid %d tried to use non-present %s\n", 67 td->td_name, td->td_proc->p_pid, s); 68 69 /* a " return nosys(p, uap); " here causes a core dump. 70 */ 71 72 return ENOSYS; 73 } 74 75 #if !defined(_KPOSIX_PRIORITY_SCHEDULING) 76 77 /* Not configured but loadable via a module: 78 */ 79 80 static int 81 sched_attach(void) 82 { 83 return 0; 84 } 85 86 SYSCALL_NOT_PRESENT_GEN(sched_setparam) 87 SYSCALL_NOT_PRESENT_GEN(sched_getparam) 88 SYSCALL_NOT_PRESENT_GEN(sched_setscheduler) 89 SYSCALL_NOT_PRESENT_GEN(sched_getscheduler) 90 SYSCALL_NOT_PRESENT_GEN(sched_yield) 91 SYSCALL_NOT_PRESENT_GEN(sched_get_priority_max) 92 SYSCALL_NOT_PRESENT_GEN(sched_get_priority_min) 93 SYSCALL_NOT_PRESENT_GEN(sched_rr_get_interval) 94 #else 95 96 /* Configured in kernel version: 97 */ 98 static struct ksched *ksched; 99 100 static int 101 sched_attach(void) 102 { 103 int ret = ksched_attach(&ksched); 104 105 if (ret == 0) 106 p31b_setcfg(CTL_P1003_1B_PRIORITY_SCHEDULING, 200112L); 107 108 return ret; 109 } 110 111 int 112 sys_sched_setparam(struct thread *td, struct sched_setparam_args *uap) 113 { 114 struct thread *targettd; 115 struct proc *targetp; 116 int e; 117 struct sched_param sched_param; 118 119 e = copyin(uap->param, &sched_param, sizeof(sched_param)); 120 if (e) 121 return (e); 122 123 if (uap->pid == 0) { 124 targetp = td->td_proc; 125 targettd = td; 126 PROC_LOCK(targetp); 127 } else { 128 targetp = pfind(uap->pid); 129 if (targetp == NULL) 130 return (ESRCH); 131 targettd = FIRST_THREAD_IN_PROC(targetp); 132 } 133 134 e = kern_sched_setparam(td, targettd, &sched_param); 135 PROC_UNLOCK(targetp); 136 return (e); 137 } 138 139 int 140 kern_sched_setparam(struct thread *td, struct thread *targettd, 141 struct sched_param *param) 142 { 143 struct proc *targetp; 144 int error; 145 146 targetp = targettd->td_proc; 147 PROC_LOCK_ASSERT(targetp, MA_OWNED); 148 149 error = p_cansched(td, targetp); 150 if (error == 0) 151 error = ksched_setparam(ksched, targettd, 152 (const struct sched_param *)param); 153 return (error); 154 } 155 156 int 157 sys_sched_getparam(struct thread *td, struct sched_getparam_args *uap) 158 { 159 int e; 160 struct sched_param sched_param; 161 struct thread *targettd; 162 struct proc *targetp; 163 164 if (uap->pid == 0) { 165 targetp = td->td_proc; 166 targettd = td; 167 PROC_LOCK(targetp); 168 } else { 169 targetp = pfind(uap->pid); 170 if (targetp == NULL) { 171 return (ESRCH); 172 } 173 targettd = FIRST_THREAD_IN_PROC(targetp); 174 } 175 176 e = kern_sched_getparam(td, targettd, &sched_param); 177 PROC_UNLOCK(targetp); 178 if (e == 0) 179 e = copyout(&sched_param, uap->param, sizeof(sched_param)); 180 return (e); 181 } 182 183 int 184 kern_sched_getparam(struct thread *td, struct thread *targettd, 185 struct sched_param *param) 186 { 187 struct proc *targetp; 188 int error; 189 190 targetp = targettd->td_proc; 191 PROC_LOCK_ASSERT(targetp, MA_OWNED); 192 193 error = p_cansee(td, targetp); 194 if (error == 0) 195 error = ksched_getparam(ksched, targettd, param); 196 return (error); 197 } 198 199 int 200 sys_sched_setscheduler(struct thread *td, struct sched_setscheduler_args *uap) 201 { 202 int e; 203 struct sched_param sched_param; 204 struct thread *targettd; 205 struct proc *targetp; 206 207 e = copyin(uap->param, &sched_param, sizeof(sched_param)); 208 if (e) 209 return (e); 210 211 if (uap->pid == 0) { 212 targetp = td->td_proc; 213 targettd = td; 214 PROC_LOCK(targetp); 215 } else { 216 targetp = pfind(uap->pid); 217 if (targetp == NULL) 218 return (ESRCH); 219 targettd = FIRST_THREAD_IN_PROC(targetp); 220 } 221 222 e = kern_sched_setscheduler(td, targettd, uap->policy, 223 &sched_param); 224 PROC_UNLOCK(targetp); 225 return (e); 226 } 227 228 int 229 kern_sched_setscheduler(struct thread *td, struct thread *targettd, 230 int policy, struct sched_param *param) 231 { 232 struct proc *targetp; 233 int error; 234 235 targetp = targettd->td_proc; 236 PROC_LOCK_ASSERT(targetp, MA_OWNED); 237 238 /* Don't allow non root user to set a scheduler policy. */ 239 error = priv_check(td, PRIV_SCHED_SET); 240 if (error) 241 return (error); 242 243 error = p_cansched(td, targetp); 244 if (error == 0) 245 error = ksched_setscheduler(ksched, targettd, policy, 246 (const struct sched_param *)param); 247 return (error); 248 } 249 250 int 251 sys_sched_getscheduler(struct thread *td, struct sched_getscheduler_args *uap) 252 { 253 int e, policy; 254 struct thread *targettd; 255 struct proc *targetp; 256 257 if (uap->pid == 0) { 258 targetp = td->td_proc; 259 targettd = td; 260 PROC_LOCK(targetp); 261 } else { 262 targetp = pfind(uap->pid); 263 if (targetp == NULL) 264 return (ESRCH); 265 targettd = FIRST_THREAD_IN_PROC(targetp); 266 } 267 268 e = kern_sched_getscheduler(td, targettd, &policy); 269 PROC_UNLOCK(targetp); 270 if (e == 0) 271 td->td_retval[0] = policy; 272 273 return (e); 274 } 275 276 int 277 kern_sched_getscheduler(struct thread *td, struct thread *targettd, 278 int *policy) 279 { 280 struct proc *targetp; 281 int error; 282 283 targetp = targettd->td_proc; 284 PROC_LOCK_ASSERT(targetp, MA_OWNED); 285 286 error = p_cansee(td, targetp); 287 if (error == 0) 288 error = ksched_getscheduler(ksched, targettd, policy); 289 return (error); 290 } 291 292 int 293 sys_sched_yield(struct thread *td, struct sched_yield_args *uap) 294 { 295 296 sched_relinquish(td); 297 return (0); 298 } 299 300 int 301 sys_sched_get_priority_max(struct thread *td, 302 struct sched_get_priority_max_args *uap) 303 { 304 int error, prio; 305 306 error = ksched_get_priority_max(ksched, uap->policy, &prio); 307 td->td_retval[0] = prio; 308 return (error); 309 } 310 311 int 312 sys_sched_get_priority_min(struct thread *td, 313 struct sched_get_priority_min_args *uap) 314 { 315 int error, prio; 316 317 error = ksched_get_priority_min(ksched, uap->policy, &prio); 318 td->td_retval[0] = prio; 319 return (error); 320 } 321 322 int 323 sys_sched_rr_get_interval(struct thread *td, 324 struct sched_rr_get_interval_args *uap) 325 { 326 struct timespec timespec; 327 int error; 328 329 error = kern_sched_rr_get_interval(td, uap->pid, ×pec); 330 if (error == 0) 331 error = copyout(×pec, uap->interval, sizeof(timespec)); 332 return (error); 333 } 334 335 int 336 kern_sched_rr_get_interval(struct thread *td, pid_t pid, 337 struct timespec *ts) 338 { 339 int e; 340 struct thread *targettd; 341 struct proc *targetp; 342 343 if (pid == 0) { 344 targettd = td; 345 targetp = td->td_proc; 346 PROC_LOCK(targetp); 347 } else { 348 targetp = pfind(pid); 349 if (targetp == NULL) 350 return (ESRCH); 351 targettd = FIRST_THREAD_IN_PROC(targetp); 352 } 353 354 e = kern_sched_rr_get_interval_td(td, targettd, ts); 355 PROC_UNLOCK(targetp); 356 return (e); 357 } 358 359 int 360 kern_sched_rr_get_interval_td(struct thread *td, struct thread *targettd, 361 struct timespec *ts) 362 { 363 struct proc *p; 364 int error; 365 366 p = targettd->td_proc; 367 PROC_LOCK_ASSERT(p, MA_OWNED); 368 369 error = p_cansee(td, p); 370 if (error == 0) 371 error = ksched_rr_get_interval(ksched, targettd, ts); 372 return (error); 373 } 374 #endif 375 376 static void 377 p31binit(void *notused) 378 { 379 (void) sched_attach(); 380 p31b_setcfg(CTL_P1003_1B_PAGESIZE, PAGE_SIZE); 381 } 382 383 SYSINIT(p31b, SI_SUB_P1003_1B, SI_ORDER_FIRST, p31binit, NULL); 384