summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkib <kib@FreeBSD.org>2010-03-19 10:56:30 +0000
committerkib <kib@FreeBSD.org>2010-03-19 10:56:30 +0000
commitd19a162142eef526ef1ad29b8939ef0b7a92d04c (patch)
treec3b82f25093a43e8d9ad116599e3b6d881c14e85
parent7932a1f757993966de97162cc026b99b93fd4d1c (diff)
downloadFreeBSD-src-d19a162142eef526ef1ad29b8939ef0b7a92d04c.zip
FreeBSD-src-d19a162142eef526ef1ad29b8939ef0b7a92d04c.tar.gz
Introduce SYSCALL_INIT_HELPER and SYSCALL32_INIT_HELPER macros and
neccessary support functions to allow registering dynamically loaded syscalls from the MOD_LOAD handlers. Helpers handle registration failures semi-automatically. Reviewed by: jhb MFC after: 2 weeks
-rw-r--r--sys/compat/freebsd32/freebsd32_misc.c30
-rw-r--r--sys/compat/freebsd32/freebsd32_util.h11
-rw-r--r--sys/kern/kern_syscalls.c30
-rw-r--r--sys/sys/sysent.h24
4 files changed, 95 insertions, 0 deletions
diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c
index 56bd02a..7a7dc2e 100644
--- a/sys/compat/freebsd32/freebsd32_misc.c
+++ b/sys/compat/freebsd32/freebsd32_misc.c
@@ -3084,6 +3084,36 @@ syscall32_module_handler(struct module *mod, int what, void *arg)
}
}
+int
+syscall32_helper_register(struct syscall_helper_data *sd)
+{
+ struct syscall_helper_data *sd1;
+ int error;
+
+ for (sd1 = sd; sd1->syscall_no != NO_SYSCALL; sd1++) {
+ error = syscall32_register(&sd1->syscall_no, &sd1->new_sysent,
+ &sd1->old_sysent);
+ if (error != 0) {
+ syscall32_helper_unregister(sd);
+ return (error);
+ }
+ sd1->registered = 1;
+ }
+ return (0);
+}
+
+int
+syscall32_helper_unregister(struct syscall_helper_data *sd)
+{
+ struct syscall_helper_data *sd1;
+
+ for (sd1 = sd; sd1->registered != 0; sd1++) {
+ syscall32_deregister(&sd1->syscall_no, &sd1->old_sysent);
+ sd1->registered = 0;
+ }
+ return (0);
+}
+
register_t *
freebsd32_copyout_strings(struct image_params *imgp)
{
diff --git a/sys/compat/freebsd32/freebsd32_util.h b/sys/compat/freebsd32/freebsd32_util.h
index 8f94612..f5ccbf1 100644
--- a/sys/compat/freebsd32/freebsd32_util.h
+++ b/sys/compat/freebsd32/freebsd32_util.h
@@ -78,10 +78,21 @@ SYSCALL32_MODULE(syscallname, \
& syscallname##_syscall32, & syscallname##_sysent32,\
NULL, NULL);
+#define SYSCALL32_INIT_HELPER(syscallname) { \
+ .new_sysent = { \
+ .sy_narg = (sizeof(struct syscallname ## _args ) \
+ / sizeof(register_t)), \
+ .sy_call = (sy_call_t *)& syscallname, \
+ }, \
+ .syscall_no = FREEBSD32_SYS_##syscallname \
+}
+
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);
+int syscall32_helper_register(struct syscall_helper_data *sd);
+int syscall32_helper_unregister(struct syscall_helper_data *sd);
register_t *freebsd32_copyout_strings(struct image_params *imgp);
struct iovec32;
diff --git a/sys/kern/kern_syscalls.c b/sys/kern/kern_syscalls.c
index 077aedc..9cb7b68 100644
--- a/sys/kern/kern_syscalls.c
+++ b/sys/kern/kern_syscalls.c
@@ -135,3 +135,33 @@ syscall_module_handler(struct module *mod, int what, void *arg)
else
return (0);
}
+
+int
+syscall_helper_register(struct syscall_helper_data *sd)
+{
+ struct syscall_helper_data *sd1;
+ int error;
+
+ for (sd1 = sd; sd1->syscall_no != NO_SYSCALL; sd1++) {
+ error = syscall_register(&sd1->syscall_no, &sd1->new_sysent,
+ &sd1->old_sysent);
+ if (error != 0) {
+ syscall_helper_unregister(sd);
+ return (error);
+ }
+ sd1->registered = 1;
+ }
+ return (0);
+}
+
+int
+syscall_helper_unregister(struct syscall_helper_data *sd)
+{
+ struct syscall_helper_data *sd1;
+
+ for (sd1 = sd; sd1->registered != 0; sd1++) {
+ syscall_deregister(&sd1->syscall_no, &sd1->old_sysent);
+ sd1->registered = 0;
+ }
+ return (0);
+}
diff --git a/sys/sys/sysent.h b/sys/sys/sysent.h
index 76cd5bd..707c00b 100644
--- a/sys/sys/sysent.h
+++ b/sys/sys/sysent.h
@@ -166,10 +166,34 @@ SYSCALL_MODULE(syscallname, \
(sysent[SYS_##syscallname].sy_call != (sy_call_t *)lkmnosys && \
sysent[SYS_##syscallname].sy_call != (sy_call_t *)lkmressys)
+/*
+ * Syscall registration helpers with resource allocation handling.
+ */
+struct syscall_helper_data {
+ struct sysent new_sysent;
+ struct sysent old_sysent;
+ int syscall_no;
+ int registered;
+};
+#define SYSCALL_INIT_HELPER(syscallname) { \
+ .new_sysent = { \
+ .sy_narg = (sizeof(struct syscallname ## _args ) \
+ / sizeof(register_t)), \
+ .sy_call = (sy_call_t *)& syscallname, \
+ .sy_auevent = SYS_AUE_##syscallname \
+ }, \
+ .syscall_no = SYS_##syscallname \
+}
+#define SYSCALL_INIT_LAST { \
+ .syscall_no = NO_SYSCALL \
+}
+
int syscall_register(int *offset, struct sysent *new_sysent,
struct sysent *old_sysent);
int syscall_deregister(int *offset, struct sysent *old_sysent);
int syscall_module_handler(struct module *mod, int what, void *arg);
+int syscall_helper_register(struct syscall_helper_data *sd);
+int syscall_helper_unregister(struct syscall_helper_data *sd);
/* Special purpose system call functions. */
struct nosys_args;
OpenPOWER on IntegriCloud