kern_syscalls.c revision 303975
1100978Srwatson/*-
2100978Srwatson * Copyright (c) 1999 Assar Westerlund
3100978Srwatson * All rights reserved.
4100978Srwatson *
5100978Srwatson * Redistribution and use in source and binary forms, with or without
6100978Srwatson * modification, are permitted provided that the following conditions
7100978Srwatson * are met:
8100978Srwatson * 1. Redistributions of source code must retain the above copyright
9100978Srwatson *    notice, this list of conditions and the following disclaimer.
10100978Srwatson * 2. Redistributions in binary form must reproduce the above copyright
11100978Srwatson *    notice, this list of conditions and the following disclaimer in the
12100978Srwatson *    documentation and/or other materials provided with the distribution.
13100978Srwatson *
14100978Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15100978Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16100978Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17100978Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18100978Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19100978Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20100978Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21100978Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22100978Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23100978Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24100978Srwatson * SUCH DAMAGE.
25100978Srwatson */
26100978Srwatson
27100978Srwatson#include <sys/cdefs.h>
28100978Srwatson__FBSDID("$FreeBSD: releng/11.0/sys/kern/kern_syscalls.c 284215 2015-06-10 10:48:12Z mjg $");
29100978Srwatson
30100978Srwatson#include <sys/param.h>
31100978Srwatson#include <sys/kernel.h>
32100978Srwatson#include <sys/lock.h>
33100978Srwatson#include <sys/module.h>
34100978Srwatson#include <sys/mutex.h>
35100978Srwatson#include <sys/proc.h>
36100978Srwatson#include <sys/resourcevar.h>
37100978Srwatson#include <sys/sx.h>
38100978Srwatson#include <sys/syscall.h>
39100978Srwatson#include <sys/sysent.h>
40100978Srwatson#include <sys/sysproto.h>
41100978Srwatson#include <sys/systm.h>
42100978Srwatson#include <machine/atomic.h>
43100978Srwatson
44100978Srwatson/*
45100978Srwatson * Acts like "nosys" but can be identified in sysent for dynamic call
46100978Srwatson * number assignment for a limited number of calls.
47100978Srwatson *
48101826Srwatson * Place holder for system call slots reserved for loadable modules.
49101826Srwatson */
50100978Srwatsonint
51100978Srwatsonlkmnosys(struct thread *td, struct nosys_args *args)
52100978Srwatson{
53100978Srwatson
54100978Srwatson	return (nosys(td, args));
55100978Srwatson}
56100978Srwatson
57100978Srwatsonint
58100978Srwatsonlkmressys(struct thread *td, struct nosys_args *args)
59100978Srwatson{
60100978Srwatson
61100978Srwatson	return (nosys(td, args));
62100978Srwatson}
63102123Srwatson
64102123Srwatsonstatic void
65102123Srwatsonsyscall_thread_drain(struct sysent *se)
66102123Srwatson{
67102123Srwatson	u_int32_t cnt, oldcnt;
68100978Srwatson
69100978Srwatson	do {
70100978Srwatson		oldcnt = se->sy_thrcnt;
71100978Srwatson		KASSERT((oldcnt & SY_THR_STATIC) == 0,
72100978Srwatson		    ("drain on static syscall"));
73100978Srwatson		cnt = oldcnt | SY_THR_DRAINING;
74100978Srwatson	} while (atomic_cmpset_acq_32(&se->sy_thrcnt, oldcnt, cnt) == 0);
75100978Srwatson	while (atomic_cmpset_32(&se->sy_thrcnt, SY_THR_DRAINING,
76100978Srwatson	    SY_THR_ABSENT) == 0)
77100978Srwatson		pause("scdrn", hz/2);
78100978Srwatson}
79100978Srwatson
80100978Srwatsonint
81100978Srwatsonsyscall_thread_enter(struct thread *td, struct sysent *se)
82100978Srwatson{
83100978Srwatson	u_int32_t cnt, oldcnt;
84100978Srwatson
85100978Srwatson	do {
86100978Srwatson		oldcnt = se->sy_thrcnt;
87100978Srwatson		if ((oldcnt & SY_THR_STATIC) != 0)
88100978Srwatson			return (0);
89100978Srwatson		if ((oldcnt & (SY_THR_DRAINING | SY_THR_ABSENT)) != 0)
90100978Srwatson			return (ENOSYS);
91100978Srwatson		cnt = oldcnt + SY_THR_INCR;
92100978Srwatson	} while (atomic_cmpset_acq_32(&se->sy_thrcnt, oldcnt, cnt) == 0);
93100978Srwatson	return (0);
94100978Srwatson}
95100978Srwatson
96100978Srwatsonvoid
97100978Srwatsonsyscall_thread_exit(struct thread *td, struct sysent *se)
98100978Srwatson{
99100978Srwatson	u_int32_t cnt, oldcnt;
100100978Srwatson
101100978Srwatson	do {
102100978Srwatson		oldcnt = se->sy_thrcnt;
103100978Srwatson		if ((oldcnt & SY_THR_STATIC) != 0)
104100978Srwatson			return;
105100978Srwatson		cnt = oldcnt - SY_THR_INCR;
106100978Srwatson	} while (atomic_cmpset_rel_32(&se->sy_thrcnt, oldcnt, cnt) == 0);
107100978Srwatson}
108100978Srwatson
109100978Srwatsonint
110100978Srwatsonsyscall_register(int *offset, struct sysent *new_sysent,
111100978Srwatson    struct sysent *old_sysent, int flags)
112100978Srwatson{
113100978Srwatson	int i;
114100978Srwatson
115100978Srwatson	if ((flags & ~SY_THR_STATIC) != 0)
116100978Srwatson		return (EINVAL);
117100978Srwatson
118100978Srwatson	if (*offset == NO_SYSCALL) {
119100978Srwatson		for (i = 1; i < SYS_MAXSYSCALL; ++i)
120100978Srwatson			if (sysent[i].sy_call == (sy_call_t *)lkmnosys)
121100978Srwatson				break;
122100978Srwatson		if (i == SYS_MAXSYSCALL)
123100978Srwatson			return (ENFILE);
124100978Srwatson		*offset = i;
125100978Srwatson	} else if (*offset < 0 || *offset >= SYS_MAXSYSCALL)
126100978Srwatson		return (EINVAL);
127100978Srwatson	else if (sysent[*offset].sy_call != (sy_call_t *)lkmnosys &&
128100978Srwatson	    sysent[*offset].sy_call != (sy_call_t *)lkmressys)
129100978Srwatson		return (EEXIST);
130100978Srwatson
131100978Srwatson	KASSERT(sysent[*offset].sy_thrcnt == SY_THR_ABSENT,
132100978Srwatson	    ("dynamic syscall is not protected"));
133100978Srwatson	*old_sysent = sysent[*offset];
134100978Srwatson	new_sysent->sy_thrcnt = SY_THR_ABSENT;
135100978Srwatson	sysent[*offset] = *new_sysent;
136100978Srwatson	atomic_store_rel_32(&sysent[*offset].sy_thrcnt, flags);
137100978Srwatson	return (0);
138100978Srwatson}
139100978Srwatson
140100978Srwatsonint
141100978Srwatsonsyscall_deregister(int *offset, struct sysent *old_sysent)
142100978Srwatson{
143100978Srwatson	struct sysent *se;
144100978Srwatson
145100978Srwatson	if (*offset == 0)
146100978Srwatson		return (0); /* XXX? */
147100978Srwatson
148100978Srwatson	se = &sysent[*offset];
149100978Srwatson	if ((se->sy_thrcnt & SY_THR_STATIC) != 0)
150100978Srwatson		return (EINVAL);
151100978Srwatson	syscall_thread_drain(se);
152100978Srwatson	sysent[*offset] = *old_sysent;
153100978Srwatson	return (0);
154100978Srwatson}
155100978Srwatson
156100978Srwatsonint
157100978Srwatsonsyscall_module_handler(struct module *mod, int what, void *arg)
158100978Srwatson{
159100978Srwatson	struct syscall_module_data *data = arg;
160100978Srwatson	modspecific_t ms;
161100978Srwatson	int error;
162100978Srwatson
163100978Srwatson	switch (what) {
164100978Srwatson	case MOD_LOAD:
165100978Srwatson		error = syscall_register(data->offset, data->new_sysent,
166100978Srwatson		    &data->old_sysent, data->flags);
167100978Srwatson		if (error) {
168100978Srwatson			/* Leave a mark so we know to safely unload below. */
169100978Srwatson			data->offset = NULL;
170100978Srwatson			return (error);
171100978Srwatson		}
172100978Srwatson		ms.intval = *data->offset;
173100978Srwatson		MOD_XLOCK;
174102123Srwatson		module_setspecific(mod, &ms);
175100978Srwatson		MOD_XUNLOCK;
176100978Srwatson		if (data->chainevh)
177100978Srwatson			error = data->chainevh(mod, what, data->chainarg);
178100978Srwatson		return (error);
179100978Srwatson	case MOD_UNLOAD:
180100978Srwatson		/*
181100978Srwatson		 * MOD_LOAD failed, so just return without calling the
182100978Srwatson		 * chained handler since we didn't pass along the MOD_LOAD
183100978Srwatson		 * event.
184100978Srwatson		 */
185100978Srwatson		if (data->offset == NULL)
186100978Srwatson			return (0);
187100978Srwatson		if (data->chainevh) {
188100978Srwatson			error = data->chainevh(mod, what, data->chainarg);
189100978Srwatson			if (error)
190100978Srwatson				return error;
191100978Srwatson		}
192100978Srwatson		error = syscall_deregister(data->offset, &data->old_sysent);
193100978Srwatson		return (error);
194100978Srwatson	default:
195100978Srwatson		if (data->chainevh)
196100978Srwatson			return (data->chainevh(mod, what, data->chainarg));
197100978Srwatson		return (EOPNOTSUPP);
198100978Srwatson	}
199100978Srwatson
200100978Srwatson	/* NOTREACHED */
201100978Srwatson}
202100978Srwatson
203104338Srwatsonint
204100978Srwatsonsyscall_helper_register(struct syscall_helper_data *sd, int flags)
205100978Srwatson{
206100978Srwatson	struct syscall_helper_data *sd1;
207100978Srwatson	int error;
208100978Srwatson
209100978Srwatson	for (sd1 = sd; sd1->syscall_no != NO_SYSCALL; sd1++) {
210100978Srwatson		error = syscall_register(&sd1->syscall_no, &sd1->new_sysent,
211100978Srwatson		    &sd1->old_sysent, flags);
212100978Srwatson		if (error != 0) {
213100978Srwatson			syscall_helper_unregister(sd);
214100978Srwatson			return (error);
215100978Srwatson		}
216100978Srwatson		sd1->registered = 1;
217100978Srwatson	}
218100978Srwatson	return (0);
219100978Srwatson}
220100978Srwatson
221100978Srwatsonint
222100978Srwatsonsyscall_helper_unregister(struct syscall_helper_data *sd)
223104541Srwatson{
224100978Srwatson	struct syscall_helper_data *sd1;
225104541Srwatson
226100978Srwatson	for (sd1 = sd; sd1->registered != 0; sd1++) {
227100978Srwatson		syscall_deregister(&sd1->syscall_no, &sd1->old_sysent);
228100978Srwatson		sd1->registered = 0;
229100978Srwatson	}
230100978Srwatson	return (0);
231100978Srwatson}
232100978Srwatson