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