kern_syscalls.c revision 205321
142433Sdfr/*- 242433Sdfr * Copyright (c) 1999 Assar Westerlund 342433Sdfr * All rights reserved. 442433Sdfr * 542433Sdfr * Redistribution and use in source and binary forms, with or without 642433Sdfr * modification, are permitted provided that the following conditions 742433Sdfr * are met: 842433Sdfr * 1. Redistributions of source code must retain the above copyright 942433Sdfr * notice, this list of conditions and the following disclaimer. 1042433Sdfr * 2. Redistributions in binary form must reproduce the above copyright 1142433Sdfr * notice, this list of conditions and the following disclaimer in the 1242433Sdfr * documentation and/or other materials provided with the distribution. 1342433Sdfr * 1442433Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1542433Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1642433Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1742433Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1842433Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1942433Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2042433Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2142433Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2242433Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2342433Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2442433Sdfr * SUCH DAMAGE. 2542433Sdfr */ 2642433Sdfr 27116182Sobrien#include <sys/cdefs.h> 28116182Sobrien__FBSDID("$FreeBSD: head/sys/kern/kern_syscalls.c 205321 2010-03-19 10:56:30Z kib $"); 29116182Sobrien 3042433Sdfr#include <sys/param.h> 3192547Sarr#include <sys/lock.h> 32183156Sjhb#include <sys/module.h> 3392547Sarr#include <sys/sx.h> 34183156Sjhb#include <sys/syscall.h> 35183156Sjhb#include <sys/sysent.h> 36183156Sjhb#include <sys/sysproto.h> 3742433Sdfr 3842756Speter/* 39183156Sjhb * Acts like "nosys" but can be identified in sysent for dynamic call 40183156Sjhb * number assignment for a limited number of calls. 41183156Sjhb * 4242756Speter * Place holder for system call slots reserved for loadable modules. 43183156Sjhb */ 4442433Sdfrint 4583366Sjulianlkmnosys(struct thread *td, struct nosys_args *args) 4642756Speter{ 47183156Sjhb 48183156Sjhb return (nosys(td, args)); 4942756Speter} 5042756Speter 5142756Speterint 5283366Sjulianlkmressys(struct thread *td, struct nosys_args *args) 5369449Salfred{ 54183156Sjhb 55183156Sjhb return (nosys(td, args)); 5669449Salfred} 5769449Salfred 5869449Salfredint 5942433Sdfrsyscall_register(int *offset, struct sysent *new_sysent, 60183156Sjhb struct sysent *old_sysent) 6142433Sdfr{ 62183156Sjhb int i; 6342433Sdfr 64183156Sjhb if (*offset == NO_SYSCALL) { 65183156Sjhb for (i = 1; i < SYS_MAXSYSCALL; ++i) 66183156Sjhb if (sysent[i].sy_call == (sy_call_t *)lkmnosys) 67183156Sjhb break; 68183156Sjhb if (i == SYS_MAXSYSCALL) 69183156Sjhb return (ENFILE); 70183156Sjhb *offset = i; 71183156Sjhb } else if (*offset < 0 || *offset >= SYS_MAXSYSCALL) 72183156Sjhb return (EINVAL); 73183156Sjhb else if (sysent[*offset].sy_call != (sy_call_t *)lkmnosys && 74183156Sjhb sysent[*offset].sy_call != (sy_call_t *)lkmressys) 75183156Sjhb return (EEXIST); 7642433Sdfr 77183156Sjhb *old_sysent = sysent[*offset]; 78183156Sjhb sysent[*offset] = *new_sysent; 79183156Sjhb return (0); 8042433Sdfr} 8142433Sdfr 8242433Sdfrint 8342433Sdfrsyscall_deregister(int *offset, struct sysent *old_sysent) 8442433Sdfr{ 85183156Sjhb 86183156Sjhb if (*offset) 87183156Sjhb sysent[*offset] = *old_sysent; 88183156Sjhb return (0); 8942433Sdfr} 9042433Sdfr 9142433Sdfrint 9242433Sdfrsyscall_module_handler(struct module *mod, int what, void *arg) 9342433Sdfr{ 94183156Sjhb struct syscall_module_data *data = arg; 95183156Sjhb modspecific_t ms; 96183156Sjhb int error; 9742433Sdfr 98183156Sjhb switch (what) { 99183156Sjhb case MOD_LOAD: 100183156Sjhb error = syscall_register(data->offset, data->new_sysent, 101183156Sjhb &data->old_sysent); 102183156Sjhb if (error) { 103183156Sjhb /* Leave a mark so we know to safely unload below. */ 104183156Sjhb data->offset = NULL; 105183156Sjhb return (error); 106183156Sjhb } 107183156Sjhb ms.intval = *data->offset; 108183156Sjhb MOD_XLOCK; 109183156Sjhb module_setspecific(mod, &ms); 110183156Sjhb MOD_XUNLOCK; 111183156Sjhb if (data->chainevh) 112183156Sjhb error = data->chainevh(mod, what, data->chainarg); 113183156Sjhb return (error); 114183156Sjhb case MOD_UNLOAD: 115183156Sjhb /* 116183156Sjhb * MOD_LOAD failed, so just return without calling the 117183156Sjhb * chained handler since we didn't pass along the MOD_LOAD 118183156Sjhb * event. 119183156Sjhb */ 120183156Sjhb if (data->offset == NULL) 121183156Sjhb return (0); 122183156Sjhb if (data->chainevh) { 123183156Sjhb error = data->chainevh(mod, what, data->chainarg); 124183156Sjhb if (error) 125183156Sjhb return error; 126183156Sjhb } 127183156Sjhb error = syscall_deregister(data->offset, &data->old_sysent); 128183156Sjhb return (error); 129183156Sjhb default: 130183156Sjhb return EOPNOTSUPP; 131183156Sjhb } 13248269Sdfr 133183156Sjhb if (data->chainevh) 134183156Sjhb return (data->chainevh(mod, what, data->chainarg)); 135183156Sjhb else 136183156Sjhb return (0); 13742433Sdfr} 138205321Skib 139205321Skibint 140205321Skibsyscall_helper_register(struct syscall_helper_data *sd) 141205321Skib{ 142205321Skib struct syscall_helper_data *sd1; 143205321Skib int error; 144205321Skib 145205321Skib for (sd1 = sd; sd1->syscall_no != NO_SYSCALL; sd1++) { 146205321Skib error = syscall_register(&sd1->syscall_no, &sd1->new_sysent, 147205321Skib &sd1->old_sysent); 148205321Skib if (error != 0) { 149205321Skib syscall_helper_unregister(sd); 150205321Skib return (error); 151205321Skib } 152205321Skib sd1->registered = 1; 153205321Skib } 154205321Skib return (0); 155205321Skib} 156205321Skib 157205321Skibint 158205321Skibsyscall_helper_unregister(struct syscall_helper_data *sd) 159205321Skib{ 160205321Skib struct syscall_helper_data *sd1; 161205321Skib 162205321Skib for (sd1 = sd; sd1->registered != 0; sd1++) { 163205321Skib syscall_deregister(&sd1->syscall_no, &sd1->old_sysent); 164205321Skib sd1->registered = 0; 165205321Skib } 166205321Skib return (0); 167205321Skib} 168