/* $NetBSD: lkm.h,v 1.43 2008/01/02 17:52:02 ad Exp $ */ /* * Header file used by loadable kernel modules and loadable kernel module * utilities. * * 23 Jan 93 Terry Lambert Original * * Copyright (c) 1992 Terrence R. Lambert. * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by Terrence R. Lambert. * 4. The name Terrence R. Lambert may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY TERRENCE R. LAMBERT ``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 TERRENCE R. LAMBERT 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. */ #ifndef _SYS_LKM_H_ #define _SYS_LKM_H_ #include <sys/queue.h> /* * Supported module types */ typedef enum loadmod { LM_SYSCALL, LM_VFS, LM_DEV, LM_STRMOD, LM_EXEC, LM_COMPAT, LM_MISC, LM_DRV } MODTYPE; #define MODTYPE_NAMES \ "SYSCALL", \ "VFS", \ "DEV", \ "STRMOD", \ "EXEC", \ "COMPAT", \ "MISC", \ "DRV" /* * Version of module interface. Bump if kernel structures or API affecting * LKM modules change, unless the kernel version is bumped at the * same time too. */ #define LKM_VERSION 2 #define MAXLKMNAME 32 /****************************************************************************/ #ifdef _KERNEL /* * Any module (to get type and name info without knowing type) */ struct lkm_any { MODTYPE lkm_type; const char *lkm_name; u_long lkm_offset; u_int lkm_modver; u_int lkm_sysver; const char *lkm_envver; }; /* * Loadable system call */ struct lkm_syscall { struct lkm_any mod; struct sysent *lkm_sysent; struct sysent lkm_oldent; /* save area for unload */ }; /* * Loadable file system */ struct lkm_vfs { struct lkm_any mod; struct vfsops *lkm_vfsops; }; /* * Loadable device driver */ struct lkm_dev { struct lkm_any mod; const char *lkm_devname; const struct bdevsw *lkm_bdev; int lkm_bdevmaj; const struct cdevsw *lkm_cdev; int lkm_cdevmaj; }; #ifdef STREAMS /* * Loadable streams module */ struct lkm_strmod { struct lkm_any mod; /* * Removed: future release */ }; #endif /* * Exec loader */ struct lkm_exec { struct lkm_any mod; struct execsw *lkm_execsw; const char *lkm_emul; }; /* * Compat (emulation) loader */ struct lkm_compat { struct lkm_any mod; const struct emul *lkm_compat; }; /* * Miscellaneous module (complex load/unload, potentially complex stat) */ struct lkm_misc { struct lkm_any mod; }; /* * Driver module */ struct lkm_drv { struct lkm_any mod; struct cfdriver **lkm_cd; const struct cfattachlkminit *lkm_cai; struct cfdata *lkm_cf; }; /* * Generic reference ala XEvent to allow single entry point in the xxxinit() * routine. */ union lkm_generic { struct lkm_any *lkm_any; struct lkm_syscall *lkm_syscall; struct lkm_vfs *lkm_vfs; struct lkm_dev *lkm_dev; #ifdef STREAMS struct lkm_strmod *lkm_strmod; #endif struct lkm_exec *lkm_exec; struct lkm_compat *lkm_compat; struct lkm_misc *lkm_misc; struct lkm_drv *lkm_drv; }; /* * Per module information structure */ struct lkm_table { char refcnt; /* Reference count */ char forced; /* Forced load, skipping compatibility check */ int (*entry)(struct lkm_table *, int, int);/* entry function */ union lkm_generic private; /* module private data */ u_long size; u_long offset; u_long area; /* ddb support */ u_long syms; /* start of symbol table */ u_long sym_size; /* size of symbol table (syms+strings) */ u_long sym_offset; /* offset of next symbol chunk */ u_long sym_symsize; /* size of symbol part only */ int id; /* Identifier */ TAILQ_ENTRY(lkm_table) link; }; #define LKM_E_LOAD 1 #define LKM_E_UNLOAD 2 #define LKM_E_STAT 3 #define MOD_SYSCALL(name,callslot,sysentp) \ static struct lkm_syscall _module = { \ { LM_SYSCALL, name, callslot, \ LKM_VERSION, __NetBSD_Version__, _LKM_ENV_VERSION }, \ sysentp \ }; #define MOD_VFS(name,vfsslot,vfsopsp) \ static struct lkm_vfs _module = { \ { LM_VFS, name, (u_long)vfsslot, \ LKM_VERSION, __NetBSD_Version__, _LKM_ENV_VERSION }, \ vfsopsp \ }; #define MOD_DEV(name,devname,bdevp,bdevm,cdevp,cdevm) \ static struct lkm_dev _module = { \ { LM_DEV, name, (u_long)-1, \ LKM_VERSION, __NetBSD_Version__, _LKM_ENV_VERSION }, \ devname, \ bdevp, \ bdevm, \ cdevp, \ cdevm, \ }; #define MOD_COMPAT(name,compatslot,emulp) \ static struct lkm_compat _module = { \ { LM_COMPAT, name, (u_long)compatslot, \ LKM_VERSION, __NetBSD_Version__, _LKM_ENV_VERSION }, \ emulp \ }; #define MOD_EXEC(name,execslot,execsw,emul) \ static struct lkm_exec _module = { \ { LM_EXEC, name, (u_long)execslot, \ LKM_VERSION, __NetBSD_Version__, _LKM_ENV_VERSION }, \ execsw, \ emul \ }; #define MOD_MISC(name) \ static struct lkm_misc _module = { \ { LM_MISC, name, (u_long)-1, \ LKM_VERSION, __NetBSD_Version__, _LKM_ENV_VERSION }, \ }; #define MOD_DRV(name,drvs,atts,cfdata) \ static struct lkm_drv _module = { \ { LM_DRV, name, (u_long)-1, \ LKM_VERSION, __NetBSD_Version__, _LKM_ENV_VERSION }, \ drvs, atts, cfdata \ }; /* * Environment encoding, for LKM<->kernel compatibility check. */ #ifdef DEBUG #define _LKM_E_DEBUG ",DEBUG" #else #define _LKM_E_DEBUG "" #endif #ifdef MALLOCLOG #define _LKM_E_MALLOCLOG ",MALLOCLOG" #else #define _LKM_E_MALLOCLOG "" #endif #define _LKM_ENV_VERSION _LKM_E_DEBUG _LKM_E_MALLOCLOG int lkm_nofunc(struct lkm_table *, int); int lkmexists(struct lkm_table *); int lkmdispatch(struct lkm_table *, int); /* * LKM_DISPATCH -- body function for use in module entry point function; * generally, the function body will consist entirely of a single * LKM_DISPATCH line. * * If load/unload/stat are called on each corresponding entry instance. * If no function is desired for load/stat/unload, lkm_nofunc() should * be specified. "cmd" is passed to each function so that a single * function can be used if desired. */ #define LKM_DISPATCH(lkmtp, cmd, envdep, load, unload, stat) \ switch (cmd) { \ int error; \ case LKM_E_LOAD: \ lkmtp->private.lkm_any = (void *)&_module; \ if ((error = lkmdispatch(lkmtp, cmd)) != 0) \ return error; \ if ((error = load(lkmtp, cmd)) != 0) \ (void)lkmdispatch(lkmtp, LKM_E_UNLOAD); \ return error; \ break; \ case LKM_E_UNLOAD: \ if ((error = unload(lkmtp, cmd)) != 0) \ return error; \ return lkmdispatch(lkmtp, cmd); \ break; \ case LKM_E_STAT: \ if ((error = stat(lkmtp, cmd)) != 0) \ return error; \ return lkmdispatch(lkmtp, cmd); \ break; \ } \ return (0); /* remap the old macro for backward source compatibility */ #define DISPATCH(lkmtp, cmd, ver, att, det, stat) \ LKM_DISPATCH(lkmtp, cmd, NULL, att, det, stat) extern struct vm_map *lkm_map; #endif /* _KERNEL */ /****************************************************************************/ /* * IOCTL's recognized by /dev/lkm */ #define LMLOADBUF _IOW('K', 1, struct lmc_loadbuf) #define LMUNRESRV _IO('K', 2) #define LMREADY _IOW('K', 3, u_long) #define LMRESERV _IOWR('K', 4, struct lmc_resrv) #define LMLOAD _IOW('K', 9, struct lmc_load) #define LMUNLOAD _IOWR('K', 10, struct lmc_unload) #define LMSTAT _IOWR('K', 11, struct lmc_stat) #define LMLOADSYMS _IOW('K', 12, struct lmc_loadbuf) #define LMFORCE _IOW('K', 13, u_long) #define MODIOBUF 512 /* # of bytes at a time to loadbuf */ /* * IOCTL arguments */ /* * Reserve a page-aligned block of kernel memory for the module */ struct lmc_resrv { u_long size; /* IN: size of module to reserve */ char *name; /* IN: name (must be provided */ int slot; /* OUT: allocated slot (module ID) */ u_long addr; /* OUT: Link-to address */ /* ddb support */ u_long xxx_unused1; /* unused */ u_long sym_size; /* IN: total size of symbol table */ u_long xxx_unused2; /* unused */ u_long sym_symsize; /* IN: size of symbol portion of symtable */ u_long sym_addr; /* OUT: address of symbol table */ }; /* * Copy a buffer at a time into the allocated area in the kernel; writes * are assumed to occur contiguously. */ struct lmc_loadbuf { int cnt; /* IN: # of chars pointed to by data */ char *data; /* IN: pointer to data buffer */ }; /* * Load a module (assumes it's been mmapped to address before call) */ struct lmc_load { void * address; /* IN: user space mmap address */ int status; /* OUT: status of operation */ int id; /* OUT: module ID if loaded */ }; /* * Unload a module (by name/id) */ struct lmc_unload { int id; /* IN: module ID to unload */ char *name; /* IN: module name to unload if id -1 */ int status; /* OUT: status of operation */ }; /* * Get module information for a given id (or name if id == -1). */ struct lmc_stat { int id; /* IN: module ID to unload */ char name[MAXLKMNAME]; /* IN/OUT: name of module */ u_long offset; /* OUT: target table offset */ MODTYPE type; /* OUT: type of module */ u_long area; /* OUT: kernel load addr */ u_long size; /* OUT: module size (pages) */ u_long private; /* OUT: module private data */ int ver; /* OUT: lkm compile version */ }; #define LKM_MAKEMAJOR(b, c) ((((b) & 0xffff) << 16) | ((c) & 0xffff)) #define LKM_BLOCK_MAJOR(v) (int)((int16_t)(((uint32_t)(v) >> 16) & 0xffff)) #define LKM_CHAR_MAJOR(v) (int)((int16_t)((v) & 0xffff)) #endif /* !_SYS_LKM_H_ */