summaryrefslogtreecommitdiffstats
path: root/sys/compat
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2008-09-25 20:50:21 +0000
committerjhb <jhb@FreeBSD.org>2008-09-25 20:50:21 +0000
commit97facf9f0e918833593afbc7a32dde456fe2ea68 (patch)
tree149c53adc50c9efe458eabd4bd1cadf0ab2b2b23 /sys/compat
parentf1ce06c8fb1bf46519e719f39617b53afb0c3ab8 (diff)
downloadFreeBSD-src-97facf9f0e918833593afbc7a32dde456fe2ea68.zip
FreeBSD-src-97facf9f0e918833593afbc7a32dde456fe2ea68.tar.gz
Add support for installing 32-bit system calls from kernel modules. This
includes syscall32_{de,}register() routines as well as a module handler and wrapper macros similar to the support for native syscalls in <sys/sysent.h>. MFC after: 1 month
Diffstat (limited to 'sys/compat')
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c80
-rw-r--r--sys/compat/freebsd32/freebsd32_util.h30
-rw-r--r--sys/compat/ia32/ia32_sysvec.c2
3 files changed, 110 insertions, 2 deletions
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 917a672..4c89d74 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -2624,3 +2624,83 @@ freebsd32_xxx(struct thread *td, struct freebsd32_xxx_args *uap)
return (error);
}
#endif
+
+int
+syscall32_register(int *offset, struct sysent *new_sysent,
+ struct sysent *old_sysent)
+{
+ if (*offset == NO_SYSCALL) {
+ int i;
+
+ for (i = 1; i < SYS_MAXSYSCALL; ++i)
+ if (freebsd32_sysent[i].sy_call ==
+ (sy_call_t *)lkmnosys)
+ break;
+ if (i == SYS_MAXSYSCALL)
+ return (ENFILE);
+ *offset = i;
+ } else if (*offset < 0 || *offset >= SYS_MAXSYSCALL)
+ return (EINVAL);
+ else if (freebsd32_sysent[*offset].sy_call != (sy_call_t *)lkmnosys &&
+ freebsd32_sysent[*offset].sy_call != (sy_call_t *)lkmressys)
+ return (EEXIST);
+
+ *old_sysent = freebsd32_sysent[*offset];
+ freebsd32_sysent[*offset] = *new_sysent;
+ return 0;
+}
+
+int
+syscall32_deregister(int *offset, struct sysent *old_sysent)
+{
+
+ if (*offset)
+ freebsd32_sysent[*offset] = *old_sysent;
+ return 0;
+}
+
+int
+syscall32_module_handler(struct module *mod, int what, void *arg)
+{
+ struct syscall_module_data *data = (struct syscall_module_data*)arg;
+ modspecific_t ms;
+ int error;
+
+ switch (what) {
+ case MOD_LOAD:
+ error = syscall32_register(data->offset, data->new_sysent,
+ &data->old_sysent);
+ if (error) {
+ /* Leave a mark so we know to safely unload below. */
+ data->offset = NULL;
+ return error;
+ }
+ ms.intval = *data->offset;
+ MOD_XLOCK;
+ module_setspecific(mod, &ms);
+ MOD_XUNLOCK;
+ if (data->chainevh)
+ error = data->chainevh(mod, what, data->chainarg);
+ return (error);
+ case MOD_UNLOAD:
+ /*
+ * MOD_LOAD failed, so just return without calling the
+ * chained handler since we didn't pass along the MOD_LOAD
+ * event.
+ */
+ if (data->offset == NULL)
+ return (0);
+ if (data->chainevh) {
+ error = data->chainevh(mod, what, data->chainarg);
+ if (error)
+ return (error);
+ }
+ error = syscall_deregister(data->offset, &data->old_sysent);
+ return (error);
+ default:
+ error = EOPNOTSUPP;
+ if (data->chainevh)
+ error = data->chainevh(mod, what, data->chainarg);
+ return (error);
+ }
+}
diff --git a/sys/compat/freebsd32/freebsd32_util.h b/sys/compat/freebsd32/freebsd32_util.h
index 5a4477f..6536b2c 100644
--- a/sys/compat/freebsd32/freebsd32_util.h
+++ b/sys/compat/freebsd32/freebsd32_util.h
@@ -53,4 +53,34 @@ struct freebsd32_ps_strings {
#define FREEBSD32_PS_STRINGS \
(FREEBSD32_USRSTACK - sizeof(struct freebsd32_ps_strings))
+extern struct sysent freebsd32_sysent[];
+
+#define SYSCALL32_MODULE(name, offset, new_sysent, evh, arg) \
+static struct syscall_module_data name##_syscall32_mod = { \
+ evh, arg, offset, new_sysent, { 0, NULL } \
+}; \
+ \
+static moduledata_t name##32_mod = { \
+ #name, \
+ syscall32_module_handler, \
+ &name##_syscall32_mod \
+}; \
+DECLARE_MODULE(name##32, name##32_mod, SI_SUB_SYSCALLS, SI_ORDER_MIDDLE)
+
+#define SYSCALL32_MODULE_HELPER(syscallname) \
+static int syscallname##_syscall32 = FREEBSD32_SYS_##syscallname; \
+static struct sysent syscallname##_sysent32 = { \
+ (sizeof(struct syscallname ## _args ) \
+ / sizeof(register_t)), \
+ (sy_call_t *)& syscallname \
+}; \
+SYSCALL32_MODULE(syscallname, \
+ & syscallname##_syscall32, & syscallname##_sysent32,\
+ NULL, NULL);
+
+int syscall32_register(int *offset, struct sysent *new_sysent,
+ struct sysent *old_sysent);
+int syscall32_deregister(int *offset, struct sysent *old_sysent);
+int syscall32_module_handler(struct module *mod, int what, void *arg);
+
#endif /* !_COMPAT_FREEBSD32_FREEBSD32_UTIL_H_ */
diff --git a/sys/compat/ia32/ia32_sysvec.c b/sys/compat/ia32/ia32_sysvec.c
index cf87b7c..ef74ba0 100644
--- a/sys/compat/ia32/ia32_sysvec.c
+++ b/sys/compat/ia32/ia32_sysvec.c
@@ -96,8 +96,6 @@ CTASSERT(sizeof(struct ia32_sigframe4) == 408);
static register_t *ia32_copyout_strings(struct image_params *imgp);
static void ia32_fixlimit(struct rlimit *rl, int which);
-extern struct sysent freebsd32_sysent[];
-
SYSCTL_NODE(_compat, OID_AUTO, ia32, CTLFLAG_RW, 0, "ia32 mode");
static u_long ia32_maxdsiz = IA32_MAXDSIZ;
OpenPOWER on IntegriCloud