14c3df794SDoug Rabson /*- 24c3df794SDoug Rabson * Copyright (c) 1999 Assar Westerlund 34c3df794SDoug Rabson * All rights reserved. 44c3df794SDoug Rabson * 54c3df794SDoug Rabson * Redistribution and use in source and binary forms, with or without 64c3df794SDoug Rabson * modification, are permitted provided that the following conditions 74c3df794SDoug Rabson * are met: 84c3df794SDoug Rabson * 1. Redistributions of source code must retain the above copyright 94c3df794SDoug Rabson * notice, this list of conditions and the following disclaimer. 104c3df794SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 114c3df794SDoug Rabson * notice, this list of conditions and the following disclaimer in the 124c3df794SDoug Rabson * documentation and/or other materials provided with the distribution. 134c3df794SDoug Rabson * 144c3df794SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 154c3df794SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 164c3df794SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 174c3df794SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 184c3df794SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 194c3df794SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 204c3df794SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 214c3df794SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 224c3df794SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 234c3df794SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 244c3df794SDoug Rabson * SUCH DAMAGE. 254c3df794SDoug Rabson */ 264c3df794SDoug Rabson 27677b542eSDavid E. O'Brien #include <sys/cdefs.h> 28677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 29677b542eSDavid E. O'Brien 304c3df794SDoug Rabson #include <sys/param.h> 31153ac44cSKonstantin Belousov #include <sys/kernel.h> 329b3851e9SAndrew R. Reiter #include <sys/lock.h> 334c3df794SDoug Rabson #include <sys/module.h> 34da672ec2SJohn Baldwin #include <sys/sx.h> 35da672ec2SJohn Baldwin #include <sys/syscall.h> 36da672ec2SJohn Baldwin #include <sys/sysent.h> 37da672ec2SJohn Baldwin #include <sys/sysproto.h> 38153ac44cSKonstantin Belousov #include <sys/systm.h> 39153ac44cSKonstantin Belousov #include <machine/atomic.h> 404c3df794SDoug Rabson 4146db4836SPeter Wemm /* 4246db4836SPeter Wemm * Acts like "nosys" but can be identified in sysent for dynamic call 4346db4836SPeter Wemm * number assignment for a limited number of calls. 4446db4836SPeter Wemm * 4546db4836SPeter Wemm * Place holder for system call slots reserved for loadable modules. 4646db4836SPeter Wemm */ 4746db4836SPeter Wemm int 48b40ce416SJulian Elischer lkmnosys(struct thread *td, struct nosys_args *args) 4946db4836SPeter Wemm { 50da672ec2SJohn Baldwin 51b40ce416SJulian Elischer return (nosys(td, args)); 5246db4836SPeter Wemm } 5346db4836SPeter Wemm 544c3df794SDoug Rabson int 55b40ce416SJulian Elischer lkmressys(struct thread *td, struct nosys_args *args) 5678525ce3SAlfred Perlstein { 57da672ec2SJohn Baldwin 58b40ce416SJulian Elischer return (nosys(td, args)); 5978525ce3SAlfred Perlstein } 6078525ce3SAlfred Perlstein 61153ac44cSKonstantin Belousov static void 62153ac44cSKonstantin Belousov syscall_thread_drain(struct sysent *se) 63153ac44cSKonstantin Belousov { 64153ac44cSKonstantin Belousov u_int32_t cnt, oldcnt; 65153ac44cSKonstantin Belousov 66153ac44cSKonstantin Belousov do { 67153ac44cSKonstantin Belousov oldcnt = se->sy_thrcnt; 68153ac44cSKonstantin Belousov KASSERT((oldcnt & SY_THR_STATIC) == 0, 69153ac44cSKonstantin Belousov ("drain on static syscall")); 70153ac44cSKonstantin Belousov cnt = oldcnt | SY_THR_DRAINING; 71153ac44cSKonstantin Belousov } while (atomic_cmpset_acq_32(&se->sy_thrcnt, oldcnt, cnt) == 0); 72153ac44cSKonstantin Belousov while (atomic_cmpset_32(&se->sy_thrcnt, SY_THR_DRAINING, 73153ac44cSKonstantin Belousov SY_THR_ABSENT) == 0) 74153ac44cSKonstantin Belousov pause("scdrn", hz/2); 75153ac44cSKonstantin Belousov } 76153ac44cSKonstantin Belousov 77153ac44cSKonstantin Belousov int 78153ac44cSKonstantin Belousov syscall_thread_enter(struct thread *td, struct sysent *se) 79153ac44cSKonstantin Belousov { 80153ac44cSKonstantin Belousov u_int32_t cnt, oldcnt; 81153ac44cSKonstantin Belousov 82153ac44cSKonstantin Belousov do { 83153ac44cSKonstantin Belousov oldcnt = se->sy_thrcnt; 84153ac44cSKonstantin Belousov if ((oldcnt & SY_THR_STATIC) != 0) 85153ac44cSKonstantin Belousov return (0); 86153ac44cSKonstantin Belousov if ((oldcnt & (SY_THR_DRAINING | SY_THR_ABSENT)) != 0) 87153ac44cSKonstantin Belousov return (ENOSYS); 88153ac44cSKonstantin Belousov cnt = oldcnt + SY_THR_INCR; 89153ac44cSKonstantin Belousov } while (atomic_cmpset_acq_32(&se->sy_thrcnt, oldcnt, cnt) == 0); 90153ac44cSKonstantin Belousov return (0); 91153ac44cSKonstantin Belousov } 92153ac44cSKonstantin Belousov 93153ac44cSKonstantin Belousov void 94153ac44cSKonstantin Belousov syscall_thread_exit(struct thread *td, struct sysent *se) 95153ac44cSKonstantin Belousov { 96153ac44cSKonstantin Belousov u_int32_t cnt, oldcnt; 97153ac44cSKonstantin Belousov 98153ac44cSKonstantin Belousov do { 99153ac44cSKonstantin Belousov oldcnt = se->sy_thrcnt; 100153ac44cSKonstantin Belousov if ((oldcnt & SY_THR_STATIC) != 0) 101153ac44cSKonstantin Belousov return; 102153ac44cSKonstantin Belousov cnt = oldcnt - SY_THR_INCR; 103153ac44cSKonstantin Belousov } while (atomic_cmpset_rel_32(&se->sy_thrcnt, oldcnt, cnt) == 0); 104153ac44cSKonstantin Belousov } 105153ac44cSKonstantin Belousov 10678525ce3SAlfred Perlstein int 1074c3df794SDoug Rabson syscall_register(int *offset, struct sysent *new_sysent, 1084c3df794SDoug Rabson struct sysent *old_sysent) 1094c3df794SDoug Rabson { 1104c3df794SDoug Rabson int i; 1114c3df794SDoug Rabson 112da672ec2SJohn Baldwin if (*offset == NO_SYSCALL) { 1134c3df794SDoug Rabson for (i = 1; i < SYS_MAXSYSCALL; ++i) 1144c3df794SDoug Rabson if (sysent[i].sy_call == (sy_call_t *)lkmnosys) 1154c3df794SDoug Rabson break; 1164c3df794SDoug Rabson if (i == SYS_MAXSYSCALL) 117da672ec2SJohn Baldwin return (ENFILE); 1184c3df794SDoug Rabson *offset = i; 1194c3df794SDoug Rabson } else if (*offset < 0 || *offset >= SYS_MAXSYSCALL) 120da672ec2SJohn Baldwin return (EINVAL); 12178525ce3SAlfred Perlstein else if (sysent[*offset].sy_call != (sy_call_t *)lkmnosys && 12278525ce3SAlfred Perlstein sysent[*offset].sy_call != (sy_call_t *)lkmressys) 123da672ec2SJohn Baldwin return (EEXIST); 1244c3df794SDoug Rabson 125153ac44cSKonstantin Belousov KASSERT(sysent[*offset].sy_thrcnt == SY_THR_ABSENT, 126153ac44cSKonstantin Belousov ("dynamic syscall is not protected")); 1274c3df794SDoug Rabson *old_sysent = sysent[*offset]; 128153ac44cSKonstantin Belousov new_sysent->sy_thrcnt = SY_THR_ABSENT; 1294c3df794SDoug Rabson sysent[*offset] = *new_sysent; 130153ac44cSKonstantin Belousov atomic_store_rel_32(&sysent[*offset].sy_thrcnt, 0); 131da672ec2SJohn Baldwin return (0); 1324c3df794SDoug Rabson } 1334c3df794SDoug Rabson 1344c3df794SDoug Rabson int 1354c3df794SDoug Rabson syscall_deregister(int *offset, struct sysent *old_sysent) 1364c3df794SDoug Rabson { 137da672ec2SJohn Baldwin 138153ac44cSKonstantin Belousov if (*offset) { 139153ac44cSKonstantin Belousov syscall_thread_drain(&sysent[*offset]); 1404c3df794SDoug Rabson sysent[*offset] = *old_sysent; 141153ac44cSKonstantin Belousov } 142da672ec2SJohn Baldwin return (0); 1434c3df794SDoug Rabson } 1444c3df794SDoug Rabson 1454c3df794SDoug Rabson int 1464c3df794SDoug Rabson syscall_module_handler(struct module *mod, int what, void *arg) 1474c3df794SDoug Rabson { 148da672ec2SJohn Baldwin struct syscall_module_data *data = arg; 149a35261efSDoug Rabson modspecific_t ms; 1504c3df794SDoug Rabson int error; 1514c3df794SDoug Rabson 1524c3df794SDoug Rabson switch (what) { 1534c3df794SDoug Rabson case MOD_LOAD: 1544c3df794SDoug Rabson error = syscall_register(data->offset, data->new_sysent, 1554c3df794SDoug Rabson &data->old_sysent); 15603e161fdSJohn Baldwin if (error) { 15703e161fdSJohn Baldwin /* Leave a mark so we know to safely unload below. */ 15803e161fdSJohn Baldwin data->offset = NULL; 159da672ec2SJohn Baldwin return (error); 16003e161fdSJohn Baldwin } 161a35261efSDoug Rabson ms.intval = *data->offset; 1629b3851e9SAndrew R. Reiter MOD_XLOCK; 163a35261efSDoug Rabson module_setspecific(mod, &ms); 1649b3851e9SAndrew R. Reiter MOD_XUNLOCK; 165c049aba8SDoug Rabson if (data->chainevh) 166c049aba8SDoug Rabson error = data->chainevh(mod, what, data->chainarg); 167da672ec2SJohn Baldwin return (error); 1684c3df794SDoug Rabson case MOD_UNLOAD: 16903e161fdSJohn Baldwin /* 17003e161fdSJohn Baldwin * MOD_LOAD failed, so just return without calling the 17103e161fdSJohn Baldwin * chained handler since we didn't pass along the MOD_LOAD 17203e161fdSJohn Baldwin * event. 17303e161fdSJohn Baldwin */ 17403e161fdSJohn Baldwin if (data->offset == NULL) 17503e161fdSJohn Baldwin return (0); 176c049aba8SDoug Rabson if (data->chainevh) { 177c049aba8SDoug Rabson error = data->chainevh(mod, what, data->chainarg); 1784c3df794SDoug Rabson if (error) 1794c3df794SDoug Rabson return error; 1804c3df794SDoug Rabson } 181c049aba8SDoug Rabson error = syscall_deregister(data->offset, &data->old_sysent); 182da672ec2SJohn Baldwin return (error); 1833e019deaSPoul-Henning Kamp default: 184*5e5fd037SXin LI if (data->chainevh) 185*5e5fd037SXin LI return (data->chainevh(mod, what, data->chainarg)); 186*5e5fd037SXin LI return (EOPNOTSUPP); 187c049aba8SDoug Rabson } 188c049aba8SDoug Rabson 18900e3c12eSXin LI /* NOTREACHED */ 1904c3df794SDoug Rabson } 1910687ba3eSKonstantin Belousov 1920687ba3eSKonstantin Belousov int 1930687ba3eSKonstantin Belousov syscall_helper_register(struct syscall_helper_data *sd) 1940687ba3eSKonstantin Belousov { 1950687ba3eSKonstantin Belousov struct syscall_helper_data *sd1; 1960687ba3eSKonstantin Belousov int error; 1970687ba3eSKonstantin Belousov 1980687ba3eSKonstantin Belousov for (sd1 = sd; sd1->syscall_no != NO_SYSCALL; sd1++) { 1990687ba3eSKonstantin Belousov error = syscall_register(&sd1->syscall_no, &sd1->new_sysent, 2000687ba3eSKonstantin Belousov &sd1->old_sysent); 2010687ba3eSKonstantin Belousov if (error != 0) { 2020687ba3eSKonstantin Belousov syscall_helper_unregister(sd); 2030687ba3eSKonstantin Belousov return (error); 2040687ba3eSKonstantin Belousov } 2050687ba3eSKonstantin Belousov sd1->registered = 1; 2060687ba3eSKonstantin Belousov } 2070687ba3eSKonstantin Belousov return (0); 2080687ba3eSKonstantin Belousov } 2090687ba3eSKonstantin Belousov 2100687ba3eSKonstantin Belousov int 2110687ba3eSKonstantin Belousov syscall_helper_unregister(struct syscall_helper_data *sd) 2120687ba3eSKonstantin Belousov { 2130687ba3eSKonstantin Belousov struct syscall_helper_data *sd1; 2140687ba3eSKonstantin Belousov 2150687ba3eSKonstantin Belousov for (sd1 = sd; sd1->registered != 0; sd1++) { 2160687ba3eSKonstantin Belousov syscall_deregister(&sd1->syscall_no, &sd1->old_sysent); 2170687ba3eSKonstantin Belousov sd1->registered = 0; 2180687ba3eSKonstantin Belousov } 2190687ba3eSKonstantin Belousov return (0); 2200687ba3eSKonstantin Belousov } 221