14c3df794SDoug Rabson /*- 24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 38a36da99SPedro F. Giffuni * 44c3df794SDoug Rabson * Copyright (c) 1999 Assar Westerlund 54c3df794SDoug Rabson * All rights reserved. 64c3df794SDoug Rabson * 74c3df794SDoug Rabson * Redistribution and use in source and binary forms, with or without 84c3df794SDoug Rabson * modification, are permitted provided that the following conditions 94c3df794SDoug Rabson * are met: 104c3df794SDoug Rabson * 1. Redistributions of source code must retain the above copyright 114c3df794SDoug Rabson * notice, this list of conditions and the following disclaimer. 124c3df794SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 134c3df794SDoug Rabson * notice, this list of conditions and the following disclaimer in the 144c3df794SDoug Rabson * documentation and/or other materials provided with the distribution. 154c3df794SDoug Rabson * 164c3df794SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 174c3df794SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 184c3df794SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 194c3df794SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 204c3df794SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 214c3df794SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 224c3df794SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 234c3df794SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 244c3df794SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 254c3df794SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 264c3df794SDoug Rabson * SUCH DAMAGE. 274c3df794SDoug Rabson */ 284c3df794SDoug Rabson 294c3df794SDoug Rabson #include <sys/param.h> 30153ac44cSKonstantin Belousov #include <sys/kernel.h> 319b3851e9SAndrew R. Reiter #include <sys/lock.h> 324c3df794SDoug Rabson #include <sys/module.h> 334ea6a9a2SMateusz Guzik #include <sys/mutex.h> 344ea6a9a2SMateusz Guzik #include <sys/proc.h> 35f6f6d240SMateusz Guzik #include <sys/resourcevar.h> 36da672ec2SJohn Baldwin #include <sys/sx.h> 37da672ec2SJohn Baldwin #include <sys/syscall.h> 38da672ec2SJohn Baldwin #include <sys/sysent.h> 39da672ec2SJohn Baldwin #include <sys/sysproto.h> 40153ac44cSKonstantin Belousov #include <sys/systm.h> 41153ac44cSKonstantin Belousov #include <machine/atomic.h> 424c3df794SDoug Rabson 4346db4836SPeter Wemm /* 4446db4836SPeter Wemm * Acts like "nosys" but can be identified in sysent for dynamic call 4546db4836SPeter Wemm * number assignment for a limited number of calls. 4646db4836SPeter Wemm * 4746db4836SPeter Wemm * Place holder for system call slots reserved for loadable modules. 4846db4836SPeter Wemm */ 4946db4836SPeter Wemm int 50b40ce416SJulian Elischer lkmnosys(struct thread *td, struct nosys_args *args) 5146db4836SPeter Wemm { 52da672ec2SJohn Baldwin 53b40ce416SJulian Elischer return (nosys(td, args)); 5446db4836SPeter Wemm } 5546db4836SPeter Wemm 564c3df794SDoug Rabson int 57b40ce416SJulian Elischer lkmressys(struct thread *td, struct nosys_args *args) 5878525ce3SAlfred Perlstein { 59da672ec2SJohn Baldwin 60b40ce416SJulian Elischer return (nosys(td, args)); 6178525ce3SAlfred Perlstein } 6278525ce3SAlfred Perlstein 63*39024a89SKonstantin Belousov struct sysent nosys_sysent = { 64*39024a89SKonstantin Belousov .sy_call = (sy_call_t *)nosys, 65*39024a89SKonstantin Belousov .sy_systrace_args_func = NULL, 66*39024a89SKonstantin Belousov .sy_narg = 0, 67*39024a89SKonstantin Belousov .sy_flags = SYF_CAPENABLED, 68*39024a89SKonstantin Belousov .sy_auevent = AUE_NULL, 69*39024a89SKonstantin Belousov .sy_entry = 0, /* DTRACE_IDNONE */ 70*39024a89SKonstantin Belousov .sy_return = 0, 71*39024a89SKonstantin Belousov .sy_thrcnt = SY_THR_STATIC, 72*39024a89SKonstantin Belousov }; 73*39024a89SKonstantin Belousov 74153ac44cSKonstantin Belousov static void 75153ac44cSKonstantin Belousov syscall_thread_drain(struct sysent *se) 76153ac44cSKonstantin Belousov { 772cee5861SJohn Baldwin uint32_t cnt, oldcnt; 78153ac44cSKonstantin Belousov 79153ac44cSKonstantin Belousov do { 80153ac44cSKonstantin Belousov oldcnt = se->sy_thrcnt; 81153ac44cSKonstantin Belousov KASSERT((oldcnt & SY_THR_STATIC) == 0, 82153ac44cSKonstantin Belousov ("drain on static syscall")); 83153ac44cSKonstantin Belousov cnt = oldcnt | SY_THR_DRAINING; 84153ac44cSKonstantin Belousov } while (atomic_cmpset_acq_32(&se->sy_thrcnt, oldcnt, cnt) == 0); 85153ac44cSKonstantin Belousov while (atomic_cmpset_32(&se->sy_thrcnt, SY_THR_DRAINING, 86153ac44cSKonstantin Belousov SY_THR_ABSENT) == 0) 87153ac44cSKonstantin Belousov pause("scdrn", hz/2); 88153ac44cSKonstantin Belousov } 89153ac44cSKonstantin Belousov 90153ac44cSKonstantin Belousov int 91*39024a89SKonstantin Belousov syscall_thread_enter(struct thread *td, struct sysent **se) 92153ac44cSKonstantin Belousov { 932cee5861SJohn Baldwin uint32_t cnt, oldcnt; 94153ac44cSKonstantin Belousov 95*39024a89SKonstantin Belousov KASSERT(((*se)->sy_thrcnt & SY_THR_STATIC) == 0, 96a1bd83feSEdward Tomasz Napierala ("%s: not a static syscall", __func__)); 97a1bd83feSEdward Tomasz Napierala 98153ac44cSKonstantin Belousov do { 99*39024a89SKonstantin Belousov oldcnt = (*se)->sy_thrcnt; 100*39024a89SKonstantin Belousov if ((oldcnt & (SY_THR_DRAINING | SY_THR_ABSENT)) != 0) { 101*39024a89SKonstantin Belousov *se = &nosys_sysent; 102*39024a89SKonstantin Belousov return (0); 103*39024a89SKonstantin Belousov } 104153ac44cSKonstantin Belousov cnt = oldcnt + SY_THR_INCR; 105*39024a89SKonstantin Belousov } while (atomic_cmpset_acq_32(&(*se)->sy_thrcnt, oldcnt, cnt) == 0); 106153ac44cSKonstantin Belousov return (0); 107153ac44cSKonstantin Belousov } 108153ac44cSKonstantin Belousov 109153ac44cSKonstantin Belousov void 110a1bd83feSEdward Tomasz Napierala syscall_thread_exit(struct thread *td, struct sysent *se) 111153ac44cSKonstantin Belousov { 1122cee5861SJohn Baldwin uint32_t cnt, oldcnt; 113153ac44cSKonstantin Belousov 114a1bd83feSEdward Tomasz Napierala KASSERT((se->sy_thrcnt & SY_THR_STATIC) == 0, 115a1bd83feSEdward Tomasz Napierala ("%s: not a static syscall", __func__)); 116a1bd83feSEdward Tomasz Napierala 117153ac44cSKonstantin Belousov do { 118153ac44cSKonstantin Belousov oldcnt = se->sy_thrcnt; 119153ac44cSKonstantin Belousov cnt = oldcnt - SY_THR_INCR; 120153ac44cSKonstantin Belousov } while (atomic_cmpset_rel_32(&se->sy_thrcnt, oldcnt, cnt) == 0); 121153ac44cSKonstantin Belousov } 122153ac44cSKonstantin Belousov 12378525ce3SAlfred Perlstein int 124b81e88d2SBrooks Davis kern_syscall_register(struct sysent *sysents, int *offset, 125b81e88d2SBrooks Davis struct sysent *new_sysent, struct sysent *old_sysent, int flags) 1264c3df794SDoug Rabson { 1274c3df794SDoug Rabson int i; 1284c3df794SDoug Rabson 129e015b1abSMateusz Guzik if ((flags & ~SY_THR_STATIC) != 0) 130e015b1abSMateusz Guzik return (EINVAL); 131e015b1abSMateusz Guzik 132da672ec2SJohn Baldwin if (*offset == NO_SYSCALL) { 1334c3df794SDoug Rabson for (i = 1; i < SYS_MAXSYSCALL; ++i) 134b81e88d2SBrooks Davis if (sysents[i].sy_call == (sy_call_t *)lkmnosys) 1354c3df794SDoug Rabson break; 1364c3df794SDoug Rabson if (i == SYS_MAXSYSCALL) 137da672ec2SJohn Baldwin return (ENFILE); 1384c3df794SDoug Rabson *offset = i; 13964ebbdd5SAndriy Gapon } else if (*offset < 0 || *offset >= SYS_MAXSYSCALL) { 140da672ec2SJohn Baldwin return (EINVAL); 14164ebbdd5SAndriy Gapon } else if (sysents[*offset].sy_call != (sy_call_t *)lkmnosys && 14264ebbdd5SAndriy Gapon sysents[*offset].sy_call != (sy_call_t *)lkmressys) { 14364ebbdd5SAndriy Gapon KASSERT(sysents[*offset].sy_call != NULL, 14464ebbdd5SAndriy Gapon ("undefined syscall %d", *offset)); 145da672ec2SJohn Baldwin return (EEXIST); 14664ebbdd5SAndriy Gapon } 1474c3df794SDoug Rabson 148b81e88d2SBrooks Davis KASSERT(sysents[*offset].sy_thrcnt == SY_THR_ABSENT, 149153ac44cSKonstantin Belousov ("dynamic syscall is not protected")); 150b81e88d2SBrooks Davis *old_sysent = sysents[*offset]; 151153ac44cSKonstantin Belousov new_sysent->sy_thrcnt = SY_THR_ABSENT; 152b81e88d2SBrooks Davis sysents[*offset] = *new_sysent; 153b81e88d2SBrooks Davis atomic_store_rel_32(&sysents[*offset].sy_thrcnt, flags); 154da672ec2SJohn Baldwin return (0); 1554c3df794SDoug Rabson } 1564c3df794SDoug Rabson 1574c3df794SDoug Rabson int 158b81e88d2SBrooks Davis kern_syscall_deregister(struct sysent *sysents, int offset, 159b81e88d2SBrooks Davis const struct sysent *old_sysent) 1604c3df794SDoug Rabson { 161e015b1abSMateusz Guzik struct sysent *se; 162da672ec2SJohn Baldwin 163b81e88d2SBrooks Davis if (offset == 0) 164e015b1abSMateusz Guzik return (0); /* XXX? */ 165e015b1abSMateusz Guzik 166b81e88d2SBrooks Davis se = &sysents[offset]; 167e015b1abSMateusz Guzik if ((se->sy_thrcnt & SY_THR_STATIC) != 0) 168e015b1abSMateusz Guzik return (EINVAL); 169e015b1abSMateusz Guzik syscall_thread_drain(se); 170a2609714SAndriy Gapon sysents[offset] = *old_sysent; 171da672ec2SJohn Baldwin return (0); 1724c3df794SDoug Rabson } 1734c3df794SDoug Rabson 1744c3df794SDoug Rabson int 1754c3df794SDoug Rabson syscall_module_handler(struct module *mod, int what, void *arg) 1764c3df794SDoug Rabson { 177b81e88d2SBrooks Davis 178b81e88d2SBrooks Davis return (kern_syscall_module_handler(sysent, mod, what, arg)); 179b81e88d2SBrooks Davis } 180b81e88d2SBrooks Davis 181b81e88d2SBrooks Davis int 182b81e88d2SBrooks Davis kern_syscall_module_handler(struct sysent *sysents, struct module *mod, 183b81e88d2SBrooks Davis int what, void *arg) 184b81e88d2SBrooks Davis { 185da672ec2SJohn Baldwin struct syscall_module_data *data = arg; 186005aa174SKa Ho Ng modspecific_t ms; 1874c3df794SDoug Rabson int error; 1884c3df794SDoug Rabson 189005aa174SKa Ho Ng bzero(&ms, sizeof(ms)); 1904c3df794SDoug Rabson switch (what) { 1914c3df794SDoug Rabson case MOD_LOAD: 192b81e88d2SBrooks Davis error = kern_syscall_register(sysents, data->offset, 193b81e88d2SBrooks Davis data->new_sysent, &data->old_sysent, data->flags); 19403e161fdSJohn Baldwin if (error) { 19503e161fdSJohn Baldwin /* Leave a mark so we know to safely unload below. */ 19603e161fdSJohn Baldwin data->offset = NULL; 197da672ec2SJohn Baldwin return (error); 19803e161fdSJohn Baldwin } 199a35261efSDoug Rabson ms.intval = *data->offset; 2009b3851e9SAndrew R. Reiter MOD_XLOCK; 201a35261efSDoug Rabson module_setspecific(mod, &ms); 2029b3851e9SAndrew R. Reiter MOD_XUNLOCK; 203c049aba8SDoug Rabson if (data->chainevh) 204c049aba8SDoug Rabson error = data->chainevh(mod, what, data->chainarg); 205da672ec2SJohn Baldwin return (error); 2064c3df794SDoug Rabson case MOD_UNLOAD: 20703e161fdSJohn Baldwin /* 20803e161fdSJohn Baldwin * MOD_LOAD failed, so just return without calling the 20903e161fdSJohn Baldwin * chained handler since we didn't pass along the MOD_LOAD 21003e161fdSJohn Baldwin * event. 21103e161fdSJohn Baldwin */ 21203e161fdSJohn Baldwin if (data->offset == NULL) 21303e161fdSJohn Baldwin return (0); 214c049aba8SDoug Rabson if (data->chainevh) { 215c049aba8SDoug Rabson error = data->chainevh(mod, what, data->chainarg); 2164c3df794SDoug Rabson if (error) 2174c3df794SDoug Rabson return error; 2184c3df794SDoug Rabson } 219b81e88d2SBrooks Davis error = kern_syscall_deregister(sysents, *data->offset, 220b81e88d2SBrooks Davis &data->old_sysent); 221da672ec2SJohn Baldwin return (error); 2223e019deaSPoul-Henning Kamp default: 2235e5fd037SXin LI if (data->chainevh) 2245e5fd037SXin LI return (data->chainevh(mod, what, data->chainarg)); 2255e5fd037SXin LI return (EOPNOTSUPP); 226c049aba8SDoug Rabson } 227c049aba8SDoug Rabson 22800e3c12eSXin LI /* NOTREACHED */ 2294c3df794SDoug Rabson } 2300687ba3eSKonstantin Belousov 2310687ba3eSKonstantin Belousov int 232e015b1abSMateusz Guzik syscall_helper_register(struct syscall_helper_data *sd, int flags) 2330687ba3eSKonstantin Belousov { 234b81e88d2SBrooks Davis 235b81e88d2SBrooks Davis return (kern_syscall_helper_register(sysent, sd, flags)); 236b81e88d2SBrooks Davis } 237b81e88d2SBrooks Davis 238b81e88d2SBrooks Davis int 239b81e88d2SBrooks Davis kern_syscall_helper_register(struct sysent *sysents, 240b81e88d2SBrooks Davis struct syscall_helper_data *sd, int flags) 241b81e88d2SBrooks Davis { 2420687ba3eSKonstantin Belousov struct syscall_helper_data *sd1; 2430687ba3eSKonstantin Belousov int error; 2440687ba3eSKonstantin Belousov 2450687ba3eSKonstantin Belousov for (sd1 = sd; sd1->syscall_no != NO_SYSCALL; sd1++) { 246b81e88d2SBrooks Davis error = kern_syscall_register(sysents, &sd1->syscall_no, 247b81e88d2SBrooks Davis &sd1->new_sysent, &sd1->old_sysent, flags); 2480687ba3eSKonstantin Belousov if (error != 0) { 249b81e88d2SBrooks Davis kern_syscall_helper_unregister(sysents, sd); 2500687ba3eSKonstantin Belousov return (error); 2510687ba3eSKonstantin Belousov } 2520687ba3eSKonstantin Belousov sd1->registered = 1; 2530687ba3eSKonstantin Belousov } 2540687ba3eSKonstantin Belousov return (0); 2550687ba3eSKonstantin Belousov } 2560687ba3eSKonstantin Belousov 2570687ba3eSKonstantin Belousov int 2580687ba3eSKonstantin Belousov syscall_helper_unregister(struct syscall_helper_data *sd) 2590687ba3eSKonstantin Belousov { 260b81e88d2SBrooks Davis 261b81e88d2SBrooks Davis return (kern_syscall_helper_unregister(sysent, sd)); 262b81e88d2SBrooks Davis } 263b81e88d2SBrooks Davis 264b81e88d2SBrooks Davis int 265b81e88d2SBrooks Davis kern_syscall_helper_unregister(struct sysent *sysents, 266b81e88d2SBrooks Davis struct syscall_helper_data *sd) 267b81e88d2SBrooks Davis { 2680687ba3eSKonstantin Belousov struct syscall_helper_data *sd1; 2690687ba3eSKonstantin Belousov 2700687ba3eSKonstantin Belousov for (sd1 = sd; sd1->registered != 0; sd1++) { 271b81e88d2SBrooks Davis kern_syscall_deregister(sysents, sd1->syscall_no, 272b81e88d2SBrooks Davis &sd1->old_sysent); 2730687ba3eSKonstantin Belousov sd1->registered = 0; 2740687ba3eSKonstantin Belousov } 2750687ba3eSKonstantin Belousov return (0); 2760687ba3eSKonstantin Belousov } 277