diff options
| -rw-r--r-- | sys/conf/Makefile.i386 | 9 | ||||
| -rw-r--r-- | sys/conf/Makefile.powerpc | 9 | ||||
| -rw-r--r-- | sys/conf/files | 3 | ||||
| -rw-r--r-- | sys/i386/conf/Makefile.i386 | 9 | ||||
| -rw-r--r-- | sys/kern/init_sysent.c | 55 | ||||
| -rw-r--r-- | sys/kern/kern_linker.c | 562 | ||||
| -rw-r--r-- | sys/kern/kern_module.c | 304 | ||||
| -rw-r--r-- | sys/kern/link_aout.c | 448 | ||||
| -rw-r--r-- | sys/kern/syscalls.c | 55 | ||||
| -rw-r--r-- | sys/kern/syscalls.master | 58 | ||||
| -rw-r--r-- | sys/sys/linker.h | 207 | ||||
| -rw-r--r-- | sys/sys/module.h | 107 | ||||
| -rw-r--r-- | sys/sys/syscall-hide.h | 10 | ||||
| -rw-r--r-- | sys/sys/syscall.h | 12 | ||||
| -rw-r--r-- | sys/sys/sysproto.h | 42 |
15 files changed, 1885 insertions, 5 deletions
diff --git a/sys/conf/Makefile.i386 b/sys/conf/Makefile.i386 index 2718b5cea838..340a05f3b436 100644 --- a/sys/conf/Makefile.i386 +++ b/sys/conf/Makefile.i386 @@ -1,7 +1,7 @@ # Makefile.i386 -- with config changes. # Copyright 1990 W. Jolitz # from: @(#)Makefile.i386 7.1 5/10/91 -# $Id: Makefile.i386,v 1.94 1997/04/22 06:55:21 jdp Exp $ +# $Id: Makefile.i386,v 1.95 1997/04/27 20:01:47 peter Exp $ # # Makefile for FreeBSD # @@ -17,6 +17,7 @@ # BINFORMAT?= aout +#BINFORMAT?= aoutkld #BINFORMAT?= elf .if exists(./@/.) @@ -70,6 +71,12 @@ SYSTEM_LD_TAIL= @echo rearranging symbols; \ symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \ size $@; chmod 755 $@ .endif +.if ${BINFORMAT} == aoutkld +SYSTEM_LD= @${LD} -Bforcedynamic -Z -T ${LOAD_ADDRESS} -o $@ -X ${SYSTEM_OBJS} vers.o +SYSTEM_LD_TAIL= @echo rearranging symbols; \ + symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \ + size $@; chmod 755 $@ +.endif .if ${BINFORMAT} == elf SYSTEM_LD= @${LD} -Bstatic -Ttext ${LOAD_ADDRESS} -e btext -o $@ -X ${SYSTEM_OBJS} vers.o SYSTEM_LD_TAIL= @size $@; chmod 755 $@ diff --git a/sys/conf/Makefile.powerpc b/sys/conf/Makefile.powerpc index 2718b5cea838..340a05f3b436 100644 --- a/sys/conf/Makefile.powerpc +++ b/sys/conf/Makefile.powerpc @@ -1,7 +1,7 @@ # Makefile.i386 -- with config changes. # Copyright 1990 W. Jolitz # from: @(#)Makefile.i386 7.1 5/10/91 -# $Id: Makefile.i386,v 1.94 1997/04/22 06:55:21 jdp Exp $ +# $Id: Makefile.i386,v 1.95 1997/04/27 20:01:47 peter Exp $ # # Makefile for FreeBSD # @@ -17,6 +17,7 @@ # BINFORMAT?= aout +#BINFORMAT?= aoutkld #BINFORMAT?= elf .if exists(./@/.) @@ -70,6 +71,12 @@ SYSTEM_LD_TAIL= @echo rearranging symbols; \ symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \ size $@; chmod 755 $@ .endif +.if ${BINFORMAT} == aoutkld +SYSTEM_LD= @${LD} -Bforcedynamic -Z -T ${LOAD_ADDRESS} -o $@ -X ${SYSTEM_OBJS} vers.o +SYSTEM_LD_TAIL= @echo rearranging symbols; \ + symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \ + size $@; chmod 755 $@ +.endif .if ${BINFORMAT} == elf SYSTEM_LD= @${LD} -Bstatic -Ttext ${LOAD_ADDRESS} -e btext -o $@ -X ${SYSTEM_OBJS} vers.o SYSTEM_LD_TAIL= @size $@; chmod 755 $@ diff --git a/sys/conf/files b/sys/conf/files index 91ea29c2fb7f..91a0663d33ac 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -48,6 +48,9 @@ kern/init_main.c standard kern/init_smp.c optional smp kern/init_sysent.c standard kern/init_sysvec.c standard +kern/kern_module.c standard +kern/kern_linker.c standard +kern/link_aout.c standard kern/kern_acct.c standard kern/kern_clock.c standard kern/kern_conf.c standard diff --git a/sys/i386/conf/Makefile.i386 b/sys/i386/conf/Makefile.i386 index 2718b5cea838..340a05f3b436 100644 --- a/sys/i386/conf/Makefile.i386 +++ b/sys/i386/conf/Makefile.i386 @@ -1,7 +1,7 @@ # Makefile.i386 -- with config changes. # Copyright 1990 W. Jolitz # from: @(#)Makefile.i386 7.1 5/10/91 -# $Id: Makefile.i386,v 1.94 1997/04/22 06:55:21 jdp Exp $ +# $Id: Makefile.i386,v 1.95 1997/04/27 20:01:47 peter Exp $ # # Makefile for FreeBSD # @@ -17,6 +17,7 @@ # BINFORMAT?= aout +#BINFORMAT?= aoutkld #BINFORMAT?= elf .if exists(./@/.) @@ -70,6 +71,12 @@ SYSTEM_LD_TAIL= @echo rearranging symbols; \ symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \ size $@; chmod 755 $@ .endif +.if ${BINFORMAT} == aoutkld +SYSTEM_LD= @${LD} -Bforcedynamic -Z -T ${LOAD_ADDRESS} -o $@ -X ${SYSTEM_OBJS} vers.o +SYSTEM_LD_TAIL= @echo rearranging symbols; \ + symorder -m ${SYMORDER_EXCLUDE} symbols.sort $@; \ + size $@; chmod 755 $@ +.endif .if ${BINFORMAT} == elf SYSTEM_LD= @${LD} -Bstatic -Ttext ${LOAD_ADDRESS} -e btext -o $@ -X ${SYSTEM_OBJS} vers.o SYSTEM_LD_TAIL= @size $@; chmod 755 $@ diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 21291c9e1b2c..a221ecf7a952 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -287,4 +287,59 @@ struct sysent sysent[] = { { 0, (sy_call_t *)nosys }, /* 252 = poll */ { 0, (sy_call_t *)issetugid }, /* 253 = issetugid */ { 3, (sy_call_t *)lchown }, /* 254 = lchown */ + { 0, (sy_call_t *)nosys }, /* 255 = nosys */ + { 0, (sy_call_t *)nosys }, /* 256 = nosys */ + { 0, (sy_call_t *)nosys }, /* 257 = nosys */ + { 0, (sy_call_t *)nosys }, /* 258 = nosys */ + { 0, (sy_call_t *)nosys }, /* 259 = nosys */ + { 0, (sy_call_t *)nosys }, /* 260 = nosys */ + { 0, (sy_call_t *)nosys }, /* 261 = nosys */ + { 0, (sy_call_t *)nosys }, /* 262 = nosys */ + { 0, (sy_call_t *)nosys }, /* 263 = nosys */ + { 0, (sy_call_t *)nosys }, /* 264 = nosys */ + { 0, (sy_call_t *)nosys }, /* 265 = nosys */ + { 0, (sy_call_t *)nosys }, /* 266 = nosys */ + { 0, (sy_call_t *)nosys }, /* 267 = nosys */ + { 0, (sy_call_t *)nosys }, /* 268 = nosys */ + { 0, (sy_call_t *)nosys }, /* 269 = nosys */ + { 0, (sy_call_t *)nosys }, /* 270 = nosys */ + { 0, (sy_call_t *)nosys }, /* 271 = nosys */ + { 0, (sy_call_t *)nosys }, /* 272 = nosys */ + { 0, (sy_call_t *)nosys }, /* 273 = nosys */ + { 0, (sy_call_t *)nosys }, /* 274 = nosys */ + { 0, (sy_call_t *)nosys }, /* 275 = nosys */ + { 0, (sy_call_t *)nosys }, /* 276 = nosys */ + { 0, (sy_call_t *)nosys }, /* 277 = nosys */ + { 0, (sy_call_t *)nosys }, /* 278 = nosys */ + { 0, (sy_call_t *)nosys }, /* 279 = nosys */ + { 0, (sy_call_t *)nosys }, /* 280 = nosys */ + { 0, (sy_call_t *)nosys }, /* 281 = nosys */ + { 0, (sy_call_t *)nosys }, /* 282 = nosys */ + { 0, (sy_call_t *)nosys }, /* 283 = nosys */ + { 0, (sy_call_t *)nosys }, /* 284 = nosys */ + { 0, (sy_call_t *)nosys }, /* 285 = nosys */ + { 0, (sy_call_t *)nosys }, /* 286 = nosys */ + { 0, (sy_call_t *)nosys }, /* 287 = nosys */ + { 0, (sy_call_t *)nosys }, /* 288 = nosys */ + { 0, (sy_call_t *)nosys }, /* 289 = nosys */ + { 0, (sy_call_t *)nosys }, /* 290 = nosys */ + { 0, (sy_call_t *)nosys }, /* 291 = nosys */ + { 0, (sy_call_t *)nosys }, /* 292 = nosys */ + { 0, (sy_call_t *)nosys }, /* 293 = nosys */ + { 0, (sy_call_t *)nosys }, /* 294 = nosys */ + { 0, (sy_call_t *)nosys }, /* 295 = nosys */ + { 0, (sy_call_t *)nosys }, /* 296 = nosys */ + { 0, (sy_call_t *)nosys }, /* 297 = nosys */ + { 0, (sy_call_t *)nosys }, /* 298 = nosys */ + { 0, (sy_call_t *)nosys }, /* 299 = nosys */ + { 1, (sy_call_t *)modnext }, /* 300 = modnext */ + { 2, (sy_call_t *)modstat }, /* 301 = modstat */ + { 1, (sy_call_t *)modfnext }, /* 302 = modfnext */ + { 1, (sy_call_t *)modfind }, /* 303 = modfind */ + { 1, (sy_call_t *)kldload }, /* 304 = kldload */ + { 1, (sy_call_t *)kldunload }, /* 305 = kldunload */ + { 1, (sy_call_t *)kldfind }, /* 306 = kldfind */ + { 1, (sy_call_t *)kldnext }, /* 307 = kldnext */ + { 2, (sy_call_t *)kldstat }, /* 308 = kldstat */ + { 1, (sy_call_t *)kldfirstmod }, /* 309 = kldfirstmod */ }; diff --git a/sys/kern/kern_linker.c b/sys/kern/kern_linker.c new file mode 100644 index 000000000000..2a4e6cdfb2f9 --- /dev/null +++ b/sys/kern/kern_linker.c @@ -0,0 +1,562 @@ +/*- + * Copyright (c) 1997 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/sysctl.h> +#include <sys/queue.h> +#include <sys/libkern.h> +#include <sys/malloc.h> +#include <sys/sysproto.h> +#include <sys/sysent.h> +#include <sys/proc.h> +#include <sys/lock.h> +#include <machine/cpu.h> +#include <sys/module.h> +#include <sys/linker.h> + +static struct lock lock; /* lock for the file list */ +static linker_class_list_t classes; +static linker_file_list_t files; +static int next_file_id = 1; + +static void +linker_init(void* arg) +{ + lockinit(&lock, PVM, "klink", 0, 0); + TAILQ_INIT(&classes); + TAILQ_INIT(&files); +} + +SYSINIT(linker, SI_SUB_KMEM, SI_ORDER_SECOND, linker_init, 0); + +int +linker_add_class(const char* desc, void* priv, + struct linker_class_ops* ops) +{ + linker_class_t lc; + + lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT); + if (!lc) + return ENOMEM; + + lc->desc = desc; + lc->priv = priv; + lc->ops = ops; + TAILQ_INSERT_HEAD(&classes, lc, link); + + return 0; +} + +static void +linker_file_sysinit(linker_file_t lf) +{ + struct linker_set* sysinits; + struct sysinit** sipp; + struct sysinit** xipp; + struct sysinit* save; + int rval[2]; /* SI_TYPE_KTHREAD support*/ + + linker_current_file = lf; + + KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", + lf->filename)); + + sysinits = (struct linker_set*) + linker_file_lookup_symbol(lf, "sysinit_set", 0); + if (!sysinits) + return; + + /* + * Perform a bubble sort of the system initialization objects by + * their subsystem (primary key) and order (secondary key). + * + * Since some things care about execution order, this is the + * operation which ensures continued function. + */ + for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { + for( xipp = sipp + 1; *xipp; xipp++) { + if( (*sipp)->subsystem < (*xipp)->subsystem || + ( (*sipp)->subsystem == (*xipp)->subsystem && + (*sipp)->order < (*xipp)->order)) + continue; /* skip*/ + save = *sipp; + *sipp = *xipp; + *xipp = save; + } + } + + + /* + * Traverse the (now) ordered list of system initialization tasks. + * Perform each task, and continue on to the next task. + * + * The last item on the list is expected to be the scheduler, + * which will not return. + */ + for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { + if( (*sipp)->subsystem == SI_SUB_DUMMY) + continue; /* skip dummy task(s)*/ + + switch( (*sipp)->type) { + case SI_TYPE_DEFAULT: + /* no special processing*/ + (*((*sipp)->func))( (*sipp)->udata); + break; + + case SI_TYPE_KTHREAD: + /* kernel thread*/ + if (fork(&proc0, NULL, rval)) + panic("fork kernel process"); + cpu_set_fork_handler(pfind(rval[0]), (*sipp)->func, (*sipp)->udata); + break; + + default: + panic( "linker_file_sysinit: unrecognized init type"); + } + } +} + +int +linker_load_file(const char* filename, linker_file_t* result) +{ + linker_class_t lc; + linker_file_t lf; + int error = 0; + + lf = linker_find_file_by_name(filename); + if (lf) { + KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename)); + *result = lf; + lf->refs++; + goto out; + } + + lf = NULL; + for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) { + KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n", + filename, lc->desc)); + if (error = lc->ops->load_file(filename, &lf)) + goto out; + if (lf) { + linker_file_sysinit(lf); + + *result = lf; + goto out; + } + } + + error = ENOEXEC; /* format not recognised */ + +out: + return error; +} + +linker_file_t +linker_find_file_by_name(const char* filename) +{ + linker_file_t lf = 0; + + lockmgr(&lock, LK_SHARED, 0, curproc); + for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) + if (!strcmp(lf->filename, filename)) + break; + lockmgr(&lock, LK_RELEASE, 0, curproc); + + return lf; +} + +linker_file_t +linker_find_file_by_id(int fileid) +{ + linker_file_t lf = 0; + + lockmgr(&lock, LK_SHARED, 0, curproc); + for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) + if (lf->id == fileid) + break; + lockmgr(&lock, LK_RELEASE, 0, curproc); + + return lf; +} + +linker_file_t +linker_make_file(const char* filename, void* priv, struct linker_file_ops* ops) +{ + linker_file_t lf = 0; + int namelen; + + KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); + lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc); + namelen = strlen(filename) + 1; + lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK); + if (!lf) + goto out; + + lf->refs = 1; + lf->userrefs = 0; + lf->filename = (char*) (lf + 1); + strcpy(lf->filename, filename); + lf->id = next_file_id++; + lf->ndeps = 0; + lf->deps = NULL; + STAILQ_INIT(&lf->common); + TAILQ_INIT(&lf->modules); + + lf->priv = priv; + lf->ops = ops; + TAILQ_INSERT_TAIL(&files, lf, link); + +out: + lockmgr(&lock, LK_RELEASE, 0, curproc); + return lf; +} + +int +linker_file_unload(linker_file_t file) +{ + module_t mod, next; + struct common_symbol* cp; + int error = 0; + int i; + + KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", lf->refs)); + lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc); + if (file->refs == 1) { + KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n")); + /* + * Inform any modules associated with this file. + */ + for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { + next = module_getfnext(mod); + + /* + * Give the module a chance to veto the unload. + */ + if (error = module_unload(mod)) { + KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n", + mod)); + lockmgr(&lock, LK_RELEASE, 0, curproc); + goto out; + } + + module_release(mod); + } + } + + file->refs--; + if (file->refs > 0) { + lockmgr(&lock, LK_RELEASE, 0, curproc); + goto out; + } + + TAILQ_REMOVE(&files, file, link); + lockmgr(&lock, LK_RELEASE, 0, curproc); + + for (i = 0; i < file->ndeps; i++) + linker_file_unload(file->deps[i]); + free(file->deps, M_LINKER); + + for (cp = STAILQ_FIRST(&file->common); cp; + cp = STAILQ_FIRST(&file->common)) { + STAILQ_REMOVE(&file->common, cp, common_symbol, link); + free(cp, M_LINKER); + } + + file->ops->unload(file); + free(file, M_LINKER); + +out: + return error; +} + +int +linker_file_add_dependancy(linker_file_t file, linker_file_t dep) +{ + linker_file_t* newdeps; + + newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*), + M_LINKER, M_WAITOK); + if (newdeps == NULL) + return ENOMEM; + + if (file->deps) { + bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*)); + free(file->deps, M_LINKER); + } + file->deps = newdeps; + file->deps[file->ndeps] = dep; + file->ndeps++; + + return 0; +} + +caddr_t +linker_file_lookup_symbol(linker_file_t file, const char* name, int deps) +{ + caddr_t address; + size_t size; + size_t common_size = 0; + int i; + + KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d", + file, name, deps)); + + if (file->ops->lookup_symbol(file, name, &address, &size) == 0) + if (address == 0) + /* + * For commons, first look them up in the dependancies and + * only allocate space if not found there. + */ + common_size = size; + else + return address; + + if (deps) + for (i = 0; i < file->ndeps; i++) { + address = linker_file_lookup_symbol(file->deps[i], name, 0); + if (address) + return address; + } + + if (common_size > 0) { + /* + * This is a common symbol which was not found in the + * dependancies. We maintain a simple common symbol table in + * the file object. + */ + struct common_symbol* cp; + + for (cp = STAILQ_FIRST(&file->common); cp; + cp = STAILQ_NEXT(cp, link)) + if (!strcmp(cp->name, name)) + return cp->address; + + /* + * Round the symbol size up to align. + */ + common_size = (common_size + sizeof(int) - 1) & -sizeof(int); + cp = malloc(sizeof(struct common_symbol) + + common_size + + strlen(name) + 1, + M_LINKER, M_WAITOK); + if (!cp) + return 0; + + cp->address = (caddr_t) (cp + 1); + cp->name = cp->address + common_size; + strcpy(cp->name, name); + bzero(cp->address, common_size); + STAILQ_INSERT_TAIL(&file->common, cp, link); + + return cp->address; + } + + return 0; +} + +/* + * Syscalls. + */ + +int +kldload(struct proc* p, struct kldload_args* uap, int* retval) +{ + char* filename = NULL; + linker_file_t lf; + int error = 0; + + *retval = -1; + + if (securelevel > 0) + return EPERM; + + if (error = suser(p->p_ucred, &p->p_acflag)) + return error; + + filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) + goto out; + + if (error = linker_load_file(uap->file, &lf)) + goto out; + + lf->userrefs++; + *retval = lf->id; + +out: + if (filename) + free(filename, M_TEMP); + return error; +} + +int +kldunload(struct proc* p, struct kldunload_args* uap, int* retval) +{ + linker_file_t lf; + int error = 0; + + if (securelevel > 0) + return EPERM; + + if (error = suser(p->p_ucred, &p->p_acflag)) + return error; + + lf = linker_find_file_by_id(SCARG(uap, fileid)); + if (lf) { + KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); + if (lf->userrefs == 0) { + printf("linkerunload: attempt to unload file which was not loaded by user\n"); + error = EBUSY; + goto out; + } + lf->userrefs--; + error = linker_file_unload(lf); + } else + error = ENOENT; + +out: + return error; +} + +int +kldfind(struct proc* p, struct kldfind_args* uap, int* retval) +{ + char* filename = NULL; + linker_file_t lf; + int error = 0; + + *retval = -1; + + filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) + goto out; + + lf = linker_find_file_by_name(filename); + if (lf) + *retval = lf->id; + else + error = ENOENT; + +out: + if (filename) + free(filename, M_TEMP); + return error; +} + +int +kldnext(struct proc* p, struct kldnext_args* uap, int* retval) +{ + linker_file_t lf; + int error = 0; + + if (SCARG(uap, fileid) == 0) { + if (TAILQ_FIRST(&files)) + *retval = TAILQ_FIRST(&files)->id; + else + *retval = 0; + return 0; + } + + lf = linker_find_file_by_id(SCARG(uap, fileid)); + if (lf) { + if (TAILQ_NEXT(lf, link)) + *retval = TAILQ_NEXT(lf, link)->id; + else + *retval = 0; + } else + error = ENOENT; + + return error; +} + +int +kldstat(struct proc* p, struct kldstat_args* uap, int* retval) +{ + linker_file_t lf; + int error = 0; + int version; + struct kld_file_stat* stat; + int namelen; + + lf = linker_find_file_by_id(SCARG(uap, fileid)); + if (!lf) { + error = ENOENT; + goto out; + } + + stat = SCARG(uap, stat); + + /* + * Check the version of the user's structure. + */ + if (error = copyin(&stat->version, &version, sizeof(version))) + goto out; + if (version != sizeof(struct kld_file_stat)) { + error = EINVAL; + goto out; + } + + namelen = strlen(lf->filename) + 1; + if (namelen > MAXPATHLEN) + namelen = MAXPATHLEN; + if (error = copyout(lf->filename, &stat->name[0], namelen)) + goto out; + if (error = copyout(&lf->refs, &stat->refs, sizeof(int))) + goto out; + if (error = copyout(&lf->id, &stat->id, sizeof(int))) + goto out; + if (error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) + goto out; + if (error = copyout(&lf->size, &stat->size, sizeof(size_t))) + goto out; + + *retval = 0; + +out: + return error; +} + +int +kldfirstmod(struct proc* p, struct kldfirstmod_args* uap, int* retval) +{ + linker_file_t lf; + int error = 0; + + lf = linker_find_file_by_id(SCARG(uap, fileid)); + if (lf) { + if (TAILQ_FIRST(&lf->modules)) + *retval = module_getid(TAILQ_FIRST(&lf->modules)); + else + *retval = 0; + } else + error = ENOENT; + + return error; +} diff --git a/sys/kern/kern_module.c b/sys/kern/kern_module.c new file mode 100644 index 000000000000..8a4048afd101 --- /dev/null +++ b/sys/kern/kern_module.c @@ -0,0 +1,304 @@ +/*- + * Copyright (c) 1997 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/sysctl.h> +#include <sys/queue.h> +#include <sys/libkern.h> +#include <sys/malloc.h> +#include <sys/sysproto.h> +#include <sys/sysent.h> +#include <sys/module.h> +#include <sys/linker.h> + +#define M_MODULE M_TEMP /* XXX */ + +typedef TAILQ_HEAD(, module) modulelist_t; +struct module { + TAILQ_ENTRY(module) link; /* chain together all modules */ + TAILQ_ENTRY(module) flink; /* all modules in a file */ + struct linker_file* file; /* file which contains this module */ + int refs; /* reference count */ + int id; /* unique id number */ + char *name; /* module name */ + modeventhand_t handler; /* event handler */ + void *arg; /* argument for handler */ +}; + +#define MOD_EVENT(mod, type) (mod)->handler((mod), (type), (mod)->arg) + +static modulelist_t modules; +static int nextid = 1; + +static void module_shutdown(int, void*); + +static void +module_init(void* arg) +{ + TAILQ_INIT(&modules); + at_shutdown(module_shutdown, 0, SHUTDOWN_POST_SYNC); +} + +SYSINIT(module, SI_SUB_KMEM, SI_ORDER_ANY, module_init, 0); + +static void +module_shutdown(int arg1, void* arg2) +{ + module_t mod; + int error; + + for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) + MOD_EVENT(mod, MOD_SHUTDOWN); +} + +void +module_register_static(void *arg) +{ + moduledata_t* data = (moduledata_t*) arg; + int error; + + if (error = module_register(data->name, data->evhand, data->priv)) + printf("module_register_static: module_register(%s, %x, %x) returned %d", + data->name, data->evhand, data->priv, error); +} + +int +module_register(const char* name, modeventhand_t handler, void* arg) +{ + size_t namelen; + module_t newmod; + int error; + + namelen = strlen(name) + 1; + newmod = (module_t) malloc(sizeof(struct module) + namelen, + M_MODULE, M_WAITOK); + if (newmod == 0) + return ENOMEM; + + newmod->refs = 1; + newmod->id = nextid++; + newmod->name = (char *) (newmod + 1); + strcpy(newmod->name, name); + newmod->handler = handler; + newmod->arg = arg; + TAILQ_INSERT_TAIL(&modules, newmod, link); + + if (linker_current_file) { + TAILQ_INSERT_TAIL(&linker_current_file->modules, newmod, flink); + newmod->file = linker_current_file; + } else + newmod->file = 0; + + if (error = MOD_EVENT(newmod, MOD_LOAD)) { + module_release(newmod); + return error; + } + + return 0; +} + +void +module_reference(module_t mod) +{ + MOD_DPF(REFS, ("module_reference: before, refs=%d\n", mod->refs)); + + mod->refs++; +} + +void +module_release(module_t mod) +{ + if (mod->refs <= 0) + panic("module_release: bad reference count"); + + MOD_DPF(REFS, ("module_release: before, refs=%d\n", mod->refs)); + + mod->refs--; + if (mod->refs == 0) { + TAILQ_REMOVE(&modules, mod, link); + if (mod->file) { + TAILQ_REMOVE(&mod->file->modules, mod, flink); + } + free(mod, M_MODULE); + } +} + +module_t +module_lookupbyname(const char* name) +{ + module_t mod; + + for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { + if (!strcmp(mod->name, name)) + return mod; + } + + return 0; +} + +module_t +module_lookupbyid(int modid) +{ + module_t mod; + + for (mod = TAILQ_FIRST(&modules); mod; mod = TAILQ_NEXT(mod, link)) { + if (mod->id == modid) + return mod; + } + + return 0; +} + +int +module_unload(module_t mod) +{ + return MOD_EVENT(mod, MOD_UNLOAD); +} + +int +module_getid(module_t mod) +{ + return mod->id; +} + +module_t +module_getfnext(module_t mod) +{ + return TAILQ_NEXT(mod, flink); +} + +/* + * Syscalls. + */ +int +modnext(struct proc* p, struct modnext_args* uap, int* retval) +{ + module_t mod; + + *retval = -1; + if (SCARG(uap, modid) == 0) { + mod = TAILQ_FIRST(&modules); + if (mod) { + *retval = mod->id; + return 0; + } else + return ENOENT; + } + + mod = module_lookupbyid(SCARG(uap, modid)); + if (!mod) + return ENOENT; + + if (TAILQ_NEXT(mod, link)) + *retval = TAILQ_NEXT(mod, link)->id; + else + *retval = 0; + return 0; +} + +int +modfnext(struct proc* p, struct modfnext_args* uap, int* retval) +{ + module_t mod; + + *retval = -1; + + mod = module_lookupbyid(SCARG(uap, modid)); + if (!mod) + return ENOENT; + + if (TAILQ_NEXT(mod, flink)) + *retval = TAILQ_NEXT(mod, flink)->id; + else + *retval = 0; + return 0; +} + +int +modstat(struct proc* p, struct modstat_args* uap, int* retval) +{ + module_t mod; + int error = 0; + int namelen; + int version; + struct module_stat* stat; + + mod = module_lookupbyid(SCARG(uap, modid)); + if (!mod) + return ENOENT; + + stat = SCARG(uap, stat); + + /* + * Check the version of the user's structure. + */ + if (error = copyin(&stat->version, &version, sizeof(version))) + goto out; + if (version != sizeof(struct module_stat)) { + error = EINVAL; + goto out; + } + + namelen = strlen(mod->name) + 1; + if (namelen > MAXMODNAME) + namelen = MAXMODNAME; + if (error = copyout(mod->name, &stat->name[0], namelen)) + goto out; + + if (error = copyout(&mod->refs, &stat->refs, sizeof(int))) + goto out; + if (error = copyout(&mod->id, &stat->id, sizeof(int))) + goto out; + + *retval = 0; + +out: + return error; +} + +int +modfind(struct proc* p, struct modfind_args* uap, int* retval) +{ + int error = 0; + char name[MAXMODNAME]; + module_t mod; + + if (error = copyinstr(SCARG(uap, name), name, sizeof name, 0)) + goto out; + + mod = module_lookupbyname(name); + if (!mod) + error = ENOENT; + else + *retval = mod->id; + +out: + return error; +} diff --git a/sys/kern/link_aout.c b/sys/kern/link_aout.c new file mode 100644 index 000000000000..5fd3f878284e --- /dev/null +++ b/sys/kern/link_aout.c @@ -0,0 +1,448 @@ +/*- + * Copyright (c) 1997 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/sysctl.h> +#include <sys/queue.h> +#include <sys/libkern.h> +#include <sys/malloc.h> +#include <sys/sysproto.h> +#include <sys/proc.h> +#include <sys/namei.h> +#include <sys/fcntl.h> +#include <sys/vnode.h> +#include <sys/linker.h> +#include <a.out.h> +#include <link.h> +#include <machine/reloc.h> +#include <sys/imgact_aout.h> + +static int link_aout_load_file(const char*, linker_file_t*); + +static int link_aout_lookup_symbol(linker_file_t, const char*, + caddr_t*, size_t*); +static void link_aout_unload(linker_file_t); + +static struct linker_class_ops link_aout_class_ops = { + link_aout_load_file, +}; + +static struct linker_file_ops link_aout_file_ops = { + link_aout_lookup_symbol, + link_aout_unload, +}; + +typedef struct aout_file { + char* address; /* Load address */ + struct _dynamic* dynamic; /* Symbol table etc. */ +} *aout_file_t; + +static int load_dependancies(linker_file_t lf); +static int relocate_file(linker_file_t lf); + +/* + * The kernel symbol table starts here. + */ +extern struct _dynamic _DYNAMIC; + +static void +link_aout_init(void* arg) +{ + struct _dynamic* dp = &_DYNAMIC; + + linker_add_class("a.out", NULL, &link_aout_class_ops); + + if (dp) { + aout_file_t af; + + af = malloc(sizeof(struct aout_file), M_LINKER, M_NOWAIT); + if (af == NULL) + panic("link_aout_init: Can't create linker structures for kernel"); + + af->address = 0; + af->dynamic = dp; + linker_kernel_file = + linker_make_file(kernelname, af, &link_aout_file_ops); + if (linker_kernel_file == NULL) + panic("link_aout_init: Can't create linker structures for kernel"); + /* + * XXX there must be a better way of getting these constants. + */ + linker_kernel_file->address = (caddr_t) 0xf0100000; + linker_kernel_file->size = -0xf0100000; + linker_current_file = linker_kernel_file; + } +} + +SYSINIT(link_aout, SI_SUB_KMEM, SI_ORDER_THIRD, link_aout_init, 0); + +int +link_aout_load_file(const char* filename, linker_file_t* result) +{ + struct nameidata nd; + struct vnode* file; + struct proc* p = curproc; /* XXX */ + int error = 0; + int resid; + struct iovec aiov; + struct uio auio; + struct exec header; + aout_file_t af; + linker_file_t lf; + + NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, filename, p); + error = vn_open(&nd, FREAD, 0); + if (error) + return error; + + /* + * Read the a.out header from the file. + */ + error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) &header, sizeof header, 0, + UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); + if (error) + goto out; + + if (N_BADMAG(header) || !(N_GETFLAG(header) & EX_DYNAMIC)) + goto out; + + /* + * We have an a.out file, so make some space to read it in. + */ + af = malloc(sizeof(struct aout_file), M_LINKER, M_WAITOK); + af->address = malloc(header.a_text + header.a_data + header.a_bss, + M_LINKER, M_WAITOK); + + /* + * Read the text and data sections and zero the bss. + */ + error = vn_rdwr(UIO_READ, nd.ni_vp, (void*) af->address, + header.a_text + header.a_data, 0, + UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); + if (error) + goto out; + bzero(af->address + header.a_text + header.a_data, header.a_bss); + + /* + * Assume _DYNAMIC is the first data item. + */ + af->dynamic = (struct _dynamic*) (af->address + header.a_text); + if (af->dynamic->d_version != LD_VERSION_BSD) { + free(af->address, M_LINKER); + free(af, M_LINKER); + goto out; + } + (long) af->dynamic->d_un.d_sdt += af->address; + + lf = linker_make_file(filename, af, &link_aout_file_ops); + if (lf == NULL) { + free(af->address, M_LINKER); + free(af, M_LINKER); + error = ENOMEM; + goto out; + } + lf->address = af->address; + lf->size = header.a_text + header.a_data + header.a_bss; + + if ((error = load_dependancies(lf)) != 0 + || (error = relocate_file(lf)) != 0) { + linker_file_unload(lf); + goto out; + } + + *result = lf; + +out: + VOP_UNLOCK(nd.ni_vp, 0, p); + vn_close(nd.ni_vp, FREAD, p->p_ucred, p); + + return error; +} + +void +link_aout_unload(linker_file_t file) +{ + aout_file_t af = file->priv; + + if (af) { + if (af->address) + free(af->address, M_LINKER); + free(af, M_LINKER); + } +} + +#define AOUT_RELOC(af, type, off) (type*) ((af)->address + (off)) + +static int +load_dependancies(linker_file_t lf) +{ + aout_file_t af = lf->priv; + linker_file_t lfdep; + long off; + struct sod* sodp; + char* name; + char* filename = 0; + int error = 0; + + /* + * All files are dependant on /kernel. + */ + linker_kernel_file->refs++; + linker_file_add_dependancy(lf, linker_kernel_file); + + off = LD_NEED(af->dynamic); + + /* + * Load the dependancies. + */ + while (off != 0) { + sodp = AOUT_RELOC(af, struct sod, off); + name = AOUT_RELOC(af, char, sodp->sod_name); + + /* + * Prepend pathname if dep is not an absolute filename. + */ + if (name[0] != '/') { + char* p; + filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); + p = lf->filename + strlen(lf->filename) - 1; + while (p >= lf->filename && *p != '/') + p--; + if (p >= lf->filename) { + strncpy(filename, lf->filename, p - lf->filename); + filename[p - lf->filename] = '\0'; + strcat(filename, "/"); + strcat(filename, name); + name = filename; + } + } + error = linker_load_file(name, &lfdep); + if (error) + goto out; + error = linker_file_add_dependancy(lf, lfdep); + if (error) + goto out; + off = sodp->sod_next; + } + +out: + if (filename) + free(filename, M_TEMP); + return error; +} + +/* + * XXX i386 dependant. + */ +static long +read_relocation(struct relocation_info* r, char* addr) +{ + int length = r->r_length; + if (length == 0) + return *(u_char*) addr; + else if (length == 1) + return *(u_short*) addr; + else if (length == 2) + return *(u_int*) addr; + else + printf("link_aout: unsupported relocation size %d\n", r->r_length); + return 0; +} + +static void +write_relocation(struct relocation_info* r, char* addr, long value) +{ + int length = r->r_length; + if (length == 0) + *(u_char*) addr = value; + else if (length == 1) + *(u_short*) addr = value; + else if (length == 2) + *(u_int*) addr = value; + else + printf("link_aout: unsupported relocation size %d\n", r->r_length); +} + +static int +relocate_file(linker_file_t lf) +{ + aout_file_t af = lf->priv; + struct relocation_info* rel; + struct relocation_info* erel; + struct relocation_info* r; + struct nzlist* symbolbase; + char* stringbase; + struct nzlist* np; + char* sym; + long relocation; + + rel = AOUT_RELOC(af, struct relocation_info, LD_REL(af->dynamic)); + erel = AOUT_RELOC(af, struct relocation_info, + LD_REL(af->dynamic) + LD_RELSZ(af->dynamic)); + symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic)); + stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic)); + + for (r = rel; r < erel; r++) { + char* addr; + + if (r->r_address == 0) + break; + + addr = AOUT_RELOC(af, char, r->r_address); + if (r->r_extern) { + np = &symbolbase[r->r_symbolnum]; + sym = &stringbase[np->nz_strx]; + + if (sym[0] != '_') { + printf("link_aout: bad symbol name %s\n", sym); + relocation = 0; + } else + relocation = (long) + linker_file_lookup_symbol(lf, sym + 1, + np->nz_type != (N_SETV+N_EXT)); + if (!relocation) { + printf("link_aout: symbol %s not found\n", sym); + return ENOENT; + } + + relocation += read_relocation(r, addr); + + if (r->r_jmptable) { + printf("link_aout: can't cope with jump table relocations\n"); + continue; + } + + if (r->r_pcrel) + relocation -= (long) af->address; + + if (r->r_copy) { + printf("link_aout: can't cope with copy relocations\n"); + continue; + } + + write_relocation(r, addr, relocation); + } else { + write_relocation(r, addr, + (long)(read_relocation(r, addr) + af->address)); + } + + } + + return 0; +} + +static long +symbol_hash_value(aout_file_t af, const char* name) +{ + long hashval; + const char* p; + + hashval = '_'; /* fake a starting '_' for C symbols */ + for (p = name; *p; p++) + hashval = (hashval << 1) + *p; + + return (hashval & 0x7fffffff) % LD_BUCKETS(af->dynamic); +} + +int +link_aout_lookup_symbol(linker_file_t file, const char* name, + caddr_t* address, size_t* size) +{ + aout_file_t af = file->priv; + int buckets; + long hashval; + struct rrs_hash* hashbase; + struct nzlist* symbolbase; + char* stringbase; + struct rrs_hash* hp; + struct nzlist* np; + char* cp; + + if (LD_BUCKETS(af->dynamic) == 0) + return NULL; + + hashbase = AOUT_RELOC(af, struct rrs_hash, LD_HASH(af->dynamic)); + symbolbase = AOUT_RELOC(af, struct nzlist, LD_SYMBOL(af->dynamic)); + stringbase = AOUT_RELOC(af, char, LD_STRINGS(af->dynamic)); + +restart: + hashval = symbol_hash_value(af, name); + hp = &hashbase[hashval]; + if (hp->rh_symbolnum == -1) + return ENOENT; + + while (hp) { + np = (struct nzlist *) &symbolbase[hp->rh_symbolnum]; + cp = stringbase + np->nz_strx; + /* + * Note: we fake the leading '_' for C symbols. + */ + if (cp[0] == '_' && !strcmp(cp + 1, name)) + break; + + if (hp->rh_next == 0) + hp = NULL; + else + hp = &hashbase[hp->rh_next]; + } + + if (hp == NULL) + /* + * Not found. + */ + return ENOENT; + + /* + * Check for an aliased symbol, whatever that is. + */ + if (np->nz_type == N_INDR+N_EXT) { + name = stringbase + (++np)->nz_strx + 1; /* +1 for '_' */ + goto restart; + } + + /* + * Check this is an actual definition of the symbol. + */ + if (np->nz_value == 0) + return ENOENT; + + if (np->nz_type == N_UNDF+N_EXT && np->nz_value != 0) { + if (np->nz_other == AUX_FUNC) + /* weak function */ + return ENOENT; + *address = 0; + *size = np->nz_value; + } else { + *address = AOUT_RELOC(af, char, np->nz_value); + *size = np->nz_size; + } + + return 0; +} diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index a3cd101dd7b3..b0b5d0889cd9 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -276,4 +276,59 @@ char *syscallnames[] = { "#252", /* 252 = poll */ "issetugid", /* 253 = issetugid */ "lchown", /* 254 = lchown */ + "#255", /* 255 = nosys */ + "#256", /* 256 = nosys */ + "#257", /* 257 = nosys */ + "#258", /* 258 = nosys */ + "#259", /* 259 = nosys */ + "#260", /* 260 = nosys */ + "#261", /* 261 = nosys */ + "#262", /* 262 = nosys */ + "#263", /* 263 = nosys */ + "#264", /* 264 = nosys */ + "#265", /* 265 = nosys */ + "#266", /* 266 = nosys */ + "#267", /* 267 = nosys */ + "#268", /* 268 = nosys */ + "#269", /* 269 = nosys */ + "#270", /* 270 = nosys */ + "#271", /* 271 = nosys */ + "#272", /* 272 = nosys */ + "#273", /* 273 = nosys */ + "#274", /* 274 = nosys */ + "#275", /* 275 = nosys */ + "#276", /* 276 = nosys */ + "#277", /* 277 = nosys */ + "#278", /* 278 = nosys */ + "#279", /* 279 = nosys */ + "#280", /* 280 = nosys */ + "#281", /* 281 = nosys */ + "#282", /* 282 = nosys */ + "#283", /* 283 = nosys */ + "#284", /* 284 = nosys */ + "#285", /* 285 = nosys */ + "#286", /* 286 = nosys */ + "#287", /* 287 = nosys */ + "#288", /* 288 = nosys */ + "#289", /* 289 = nosys */ + "#290", /* 290 = nosys */ + "#291", /* 291 = nosys */ + "#292", /* 292 = nosys */ + "#293", /* 293 = nosys */ + "#294", /* 294 = nosys */ + "#295", /* 295 = nosys */ + "#296", /* 296 = nosys */ + "#297", /* 297 = nosys */ + "#298", /* 298 = nosys */ + "#299", /* 299 = nosys */ + "modnext", /* 300 = modnext */ + "modstat", /* 301 = modstat */ + "modfnext", /* 302 = modfnext */ + "modfind", /* 303 = modfind */ + "kldload", /* 304 = kldload */ + "kldunload", /* 305 = kldunload */ + "kldfind", /* 306 = kldfind */ + "kldnext", /* 307 = kldnext */ + "kldstat", /* 308 = kldstat */ + "kldfirstmod", /* 309 = kldfirstmod */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index fc02d31b4401..dcd916b794e2 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -1,4 +1,4 @@ - $Id: syscalls.master,v 1.34 1997/03/31 12:14:48 peter Exp $ + $Id: syscalls.master,v 1.35 1997/03/31 14:52:50 peter Exp $ ; from: @(#)syscalls.master 8.2 (Berkeley) 1/13/94 ; ; System call name/number master file. @@ -393,3 +393,59 @@ 252 UNIMPL NOHIDE poll (OpenBSD) 253 STD BSD { int issetugid(void); } 254 STD BSD { int lchown(char *path, int uid, int gid); } +255 UNIMPL NOHIDE nosys +256 UNIMPL NOHIDE nosys +257 UNIMPL NOHIDE nosys +258 UNIMPL NOHIDE nosys +259 UNIMPL NOHIDE nosys +260 UNIMPL NOHIDE nosys +261 UNIMPL NOHIDE nosys +262 UNIMPL NOHIDE nosys +263 UNIMPL NOHIDE nosys +264 UNIMPL NOHIDE nosys +265 UNIMPL NOHIDE nosys +266 UNIMPL NOHIDE nosys +267 UNIMPL NOHIDE nosys +268 UNIMPL NOHIDE nosys +269 UNIMPL NOHIDE nosys +270 UNIMPL NOHIDE nosys +271 UNIMPL NOHIDE nosys +272 UNIMPL NOHIDE nosys +273 UNIMPL NOHIDE nosys +274 UNIMPL NOHIDE nosys +275 UNIMPL NOHIDE nosys +276 UNIMPL NOHIDE nosys +277 UNIMPL NOHIDE nosys +278 UNIMPL NOHIDE nosys +279 UNIMPL NOHIDE nosys +280 UNIMPL NOHIDE nosys +281 UNIMPL NOHIDE nosys +282 UNIMPL NOHIDE nosys +283 UNIMPL NOHIDE nosys +284 UNIMPL NOHIDE nosys +285 UNIMPL NOHIDE nosys +286 UNIMPL NOHIDE nosys +287 UNIMPL NOHIDE nosys +288 UNIMPL NOHIDE nosys +289 UNIMPL NOHIDE nosys +290 UNIMPL NOHIDE nosys +291 UNIMPL NOHIDE nosys +292 UNIMPL NOHIDE nosys +293 UNIMPL NOHIDE nosys +294 UNIMPL NOHIDE nosys +295 UNIMPL NOHIDE nosys +296 UNIMPL NOHIDE nosys +297 UNIMPL NOHIDE nosys +298 UNIMPL NOHIDE nosys +299 UNIMPL NOHIDE nosys +; syscall numbers for FreeBSD +300 STD BSD { int modnext(int modid); } +301 STD BSD { int modstat(int modid, struct module_stat* stat); } +302 STD BSD { int modfnext(int modid); } +303 STD BSD { int modfind(char *name); } +304 STD BSD { int kldload(const char *file); } +305 STD BSD { int kldunload(int fileid); } +306 STD BSD { int kldfind(const char *file); } +307 STD BSD { int kldnext(int fileid); } +308 STD BSD { int kldstat(int fileid, struct kld_file_stat* stat); } +309 STD BSD { int kldfirstmod(int fileid); } diff --git a/sys/sys/linker.h b/sys/sys/linker.h new file mode 100644 index 000000000000..d1862424e0f2 --- /dev/null +++ b/sys/sys/linker.h @@ -0,0 +1,207 @@ +/*- + * Copyright (c) 1997 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#ifndef _SYS_LINKER_H_ +#define _SYS_LINKER_H_ + +#ifdef KERNEL + +#define M_LINKER M_TEMP /* XXX */ + +/* + * Object representing a file which has been loaded by the linker. + */ +typedef struct linker_file* linker_file_t; +typedef TAILQ_HEAD(, linker_file) linker_file_list_t; + +struct linker_file_ops { + /* + * Lookup a symbol in the file's symbol table. If the symbol is + * not found then return ENOENT, otherwise zero. If the symbol + * found is a common symbol, return with *address set to zero and + * *size set to the size of the common space required. Otherwise + * set *address the value of the symbol. + */ + int (*lookup_symbol)(linker_file_t, const char* name, + caddr_t* address, size_t* size); + + /* + * Unload a file, releasing dependancies and freeing storage. + */ + void (*unload)(linker_file_t); +}; + +struct common_symbol { + STAILQ_ENTRY(common_symbol) link; + char* name; + caddr_t address; +}; + +struct linker_file { + int refs; /* reference count */ + int userrefs; /* modload(2) count */ + TAILQ_ENTRY(linker_file) link; /* list of all loaded files */ + char* filename; /* file which was loaded */ + int id; /* unique id */ + caddr_t address; /* load address */ + size_t size; /* size of file */ + int ndeps; /* number of dependancies */ + linker_file_t* deps; /* list of dependancies */ + STAILQ_HEAD(, common_symbol) common; /* list of common symbols */ + TAILQ_HEAD(, module) modules; /* modules in this file */ + void* priv; /* implementation data */ + + struct linker_file_ops* ops; +}; + +/* + * Object implementing a class of file (a.out, elf, etc.) + */ +typedef struct linker_class *linker_class_t; +typedef TAILQ_HEAD(, linker_class) linker_class_list_t; + +struct linker_class_ops { + /* + * Load a file, returning the new linker_file_t in *result. If + * the class does not recognise the file type, zero should be + * returned, without modifying *result. If the file is + * recognised, the file should be loaded, *result set to the new + * file and zero returned. If some other error is detected an + * appropriate errno should be returned. + */ + int (*load_file)(const char* filename, linker_file_t* result); +}; + +struct linker_class { + TAILQ_ENTRY(linker_class) link; /* list of all file classes */ + const char* desc; /* description (e.g. "a.out") */ + void* priv; /* implementation data */ + + struct linker_class_ops *ops; +}; + +/* + * The file representing the currently running kernel. This contains + * the global symbol table. + */ +linker_file_t linker_kernel_file; + +/* + * The file which is currently loading. Used to register modules with + * the files which contain them. + */ +linker_file_t linker_current_file; + +/* + * Add a new file class to the linker. + */ +int linker_add_class(const char* desc, void* priv, + struct linker_class_ops* ops); + +/* + * Load a file, trying each file class until one succeeds. + */ +int linker_load_file(const char* filename, linker_file_t* result); + +/* + * Find a currently loaded file given its filename. + */ +linker_file_t linker_find_file_by_name(const char* filename); + +/* + * Find a currently loaded file given its file id. + */ +linker_file_t linker_find_file_by_id(int fileid); + +/* + * Called from a class handler when a file is laoded. + */ +linker_file_t linker_make_file(const char* filename, void* priv, + struct linker_file_ops* ops); + +/* + * Unload a file, freeing up memory. + */ +int linker_file_unload(linker_file_t file); + +/* + * Add a dependancy to a file. + */ +int linker_file_add_dependancy(linker_file_t file, linker_file_t dep); + +/* + * Lookup a symbol in a file. If deps is TRUE, look in dependancies + * if not found in file. + */ +caddr_t linker_file_lookup_symbol(linker_file_t file, const char* name, + int deps); + +#ifdef KLD_DEBUG + +extern int kld_debug; +#define KLD_DEBUG_FILE 1 /* file load/unload */ +#define KLD_DEBUG_SYM 2 /* symbol lookup */ + +#define KLD_DPF(cat, args) \ + do { \ + if (KLD_debug & KLD_DEBUG_##cat) printf args; \ + } while (0) + +#else + +#define KLD_DPF(cat, args) + +#endif + +#endif /* KERNEL */ + +struct kld_file_stat { + int version; /* set to sizeof(linker_file_stat) */ + char name[MAXPATHLEN]; + int refs; + int id; + caddr_t address; /* load address */ + size_t size; /* size in bytes */ +}; + +#ifndef KERNEL + +#include <sys/cdefs.h> + +__BEGIN_DECLS +int kldload(const char* file); +int kldunload(int fileid); +int kldfind(const char* file); +int kldnext(int fileid); +int kldstat(int fileid, struct kld_file_stat* stat); +int kldfirstmod(int fileid); +__END_DECLS + +#endif + +#endif /* !_SYS_KLD_H_ */ diff --git a/sys/sys/module.h b/sys/sys/module.h new file mode 100644 index 000000000000..643621204d3f --- /dev/null +++ b/sys/sys/module.h @@ -0,0 +1,107 @@ +/*- + * Copyright (c) 1997 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#ifndef _SYS_MODULE_H_ +#define _SYS_MODULE_H_ + +#ifdef KERNEL + +typedef enum { + MOD_LOAD, + MOD_UNLOAD, + MOD_SHUTDOWN +} modeventtype_t; + +struct module; +typedef struct module *module_t; + +typedef int (*modeventhand_t)(module_t mod, modeventtype_t what, void *arg); + +/* + * Struct for registering modules statically via SYSINIT. + */ +typedef struct moduledata { + char* name; /* module name */ + modeventhand_t evhand; /* event handler */ + void* priv; /* extra data */ +} moduledata_t; + +#define DECLARE_MODULE(name, data, sub, order) \ +SYSINIT(name##module, sub, order, module_register_static, &data) + +void module_register_static(void *data); +int module_register(const char *name, modeventhand_t callback, void *arg); +module_t module_lookupbyname(const char *name); +module_t module_lookupbyid(int modid); +void module_reference(module_t mod); +void module_release(module_t mod); +int module_unload(module_t mod); +int module_getid(module_t mod); +module_t module_getfnext(module_t mod); + +#ifdef MOD_DEBUG + +extern int mod_debug; +#define MOD_DEBUG_REFS 1 + +#define MOD_DPF(cat, args) \ + do { \ + if (mod_debug & MOD_DEBUG_##cat) printf args; \ + } while (0) + +#else + +#define MOD_DPF(cat, args) + +#endif + +#endif /* KERNEL */ + +#define MAXMODNAME 32 + +struct module_stat { + int version; /* set to sizeof(struct module_stat) */ + char name[MAXMODNAME]; + int refs; + int id; +}; + +#ifndef KERNEL + +#include <sys/cdefs.h> + +__BEGIN_DECLS +int modnext(int modid); +int modfnext(int modid); +int modstat(int modid, struct module_stat* stat); +int modfind(char *name); +__END_DECLS + +#endif + +#endif /* !_SYS_MODULE_H_ */ diff --git a/sys/sys/syscall-hide.h b/sys/sys/syscall-hide.h index 99f9f46dcd81..6d6aacd63b7b 100644 --- a/sys/sys/syscall-hide.h +++ b/sys/sys/syscall-hide.h @@ -214,3 +214,13 @@ HIDE_BSD(minherit) HIDE_BSD(rfork) HIDE_BSD(issetugid) HIDE_BSD(lchown) +HIDE_BSD(modnext) +HIDE_BSD(modstat) +HIDE_BSD(modfnext) +HIDE_BSD(modfind) +HIDE_BSD(kldload) +HIDE_BSD(kldunload) +HIDE_BSD(kldfind) +HIDE_BSD(kldnext) +HIDE_BSD(kldstat) +HIDE_BSD(kldfirstmod) diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index 1ae2aa1417c2..90e4254149bf 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -208,4 +208,14 @@ #define SYS_rfork 251 #define SYS_issetugid 253 #define SYS_lchown 254 -#define SYS_MAXSYSCALL 255 +#define SYS_modnext 300 +#define SYS_modstat 301 +#define SYS_modfnext 302 +#define SYS_modfind 303 +#define SYS_kldload 304 +#define SYS_kldunload 305 +#define SYS_kldfind 306 +#define SYS_kldnext 307 +#define SYS_kldstat 308 +#define SYS_kldfirstmod 309 +#define SYS_MAXSYSCALL 310 diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index ba02baf6a677..f278eb945141 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -733,6 +733,38 @@ struct lchown_args { int uid; int gid; }; +struct modnext_args { + int modid; +}; +struct modstat_args { + int modid; + struct module_stat * stat; +}; +struct modfnext_args { + int modid; +}; +struct modfind_args { + char * name; +}; +struct kldload_args { + const char * file; +}; +struct kldunload_args { + int fileid; +}; +struct kldfind_args { + const char * file; +}; +struct kldnext_args { + int fileid; +}; +struct kldstat_args { + int fileid; + struct kld_file_stat * stat; +}; +struct kldfirstmod_args { + int fileid; +}; int nosys __P((struct proc *, struct nosys_args *, int [])); void exit __P((struct proc *, struct rexit_args *, int [])) __dead2; int fork __P((struct proc *, struct fork_args *, int [])); @@ -905,6 +937,16 @@ int minherit __P((struct proc *, struct minherit_args *, int [])); int rfork __P((struct proc *, struct rfork_args *, int [])); int issetugid __P((struct proc *, struct issetugid_args *, int [])); int lchown __P((struct proc *, struct lchown_args *, int [])); +int modnext __P((struct proc *, struct modnext_args *, int [])); +int modstat __P((struct proc *, struct modstat_args *, int [])); +int modfnext __P((struct proc *, struct modfnext_args *, int [])); +int modfind __P((struct proc *, struct modfind_args *, int [])); +int kldload __P((struct proc *, struct kldload_args *, int [])); +int kldunload __P((struct proc *, struct kldunload_args *, int [])); +int kldfind __P((struct proc *, struct kldfind_args *, int [])); +int kldnext __P((struct proc *, struct kldnext_args *, int [])); +int kldstat __P((struct proc *, struct kldstat_args *, int [])); +int kldfirstmod __P((struct proc *, struct kldfirstmod_args *, int [])); #ifdef COMPAT_43 |
