Dynamic Kernel Linker Facility - Kernel Modules KLD Device Drivers • The kld interface allows system administrators to dynamically add and remove functionality from a Pseudo device example running system. Joystick device example • This allows device driver writers to load their new changes into a running kernel without constantly rebooting to test changes. • kld interface is used through the following privileged commands: – kldload - loads a new kernel module – kldunload - unloads a kernel module – kldstat - lists the currently loaded modules The loader Skeleton Layout of a kernel module /* * Load handler that deals with the loading and unloading of a KLD. */ /* * KLD Skeleton * Inspired by Andrew Reiter's Daemonnews article */ #include <sys/types.h> static int skel_loader(struct module *m, int what, void *arg) #include <sys/module.h> { #include <sys/systm.h> /* uprintf */ int err = 0; #include <sys/errno.h> switch (what) { #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ case MOD_LOAD: /* kldload */ uprintf("Skeleton KLD loaded.\n"); / * Load handler that deals with the loading and unloading of a KLD. */ break; static int skel_loader(struct module *m, int what, void *arg) case MOD_UNLOAD: { int err = 0; uprintf("Skeleton KLD unloaded.\n"); switch (what) { break; case MOD_LOAD: /* kldload */ default: uprintf("Skeleton KLD loaded.\n"); break; err = EINVAL; case MOD_UNLOAD: uprintf("Skeleton KLD unloaded.\n"); break; default: err = break; EINVAL; break; } return(err); } /* Declare this module to the rest of the kernel */ static } moduledata_t skel_mod = { "skel", skel_loader, NULL }; DECLARE_MODULE(skeleton, skel_mod, SI_SUB_KLD, SI_ORDER_ANY); return(err); } } Declaring the module Compiling and Loading • The makefile should look like: /* Declare this module to the rest of the kernel */ SRCS=skeleton.c KMOD=skeleton static moduledata_t skel_mod = .include <bsd.kmod.mk> { "skel", skel_loader, NULL }; • Running make with this makefile will DECLARE_MODULE(skeleton, skel_mod, create a file skeleton.ko SI_SUB_KLD, SI_ORDER_ANY); • It can be loaded into your system by typing: # kldload -v ./skeleton.ko 1
what's in a mode Special Files struct stat { dev_t st_dev; /* inode's device */ • hardware devices have file names. ino_t st_ino; /* inode's number */ mode_t st_mode; /* inode protection mode */ – /dev/tty nlink_t st_nlink; /* number of hard links */ uid_t st_uid; /* user ID of the file's owner */ – /dev/ad0s1a gid_t st_gid; /* group ID of the file's group */ – /dev/zero dev_t st_rdev; /* device type */ ... • may be accessed by the same system calls } used for regular files ... #define S_ISDIR(m) ((m & 0170000) == 0040000) /* directory */ • created by the mknode system call. #define S_ISCHR(m) ((m & 0170000) == 0020000) /* char special */ #define S_ISBLK(m) ((m & 0170000) == 0060000) /* block special */ • MAKEDEV script. #define S_ISREG(m) ((m & 0170000) == 0100000) /* regular file */ #define S_ISFIFO(m) ((m & 0170000) == 0010000 || \ • can be: (m & 0170000) == 0140000) /* fifo or socket */ #ifndef _POSIX_SOURCE – structured - blocked oriented #define S_ISLNK(m) ((m & 0170000) == 0120000) /* symbolic link */ #define S_ISSOCK(m) ((m & 0170000) == 0010000 || \ – unstructured - character oriented (m & 0170000) == 0140000) /* fifo or socket */ #define S_ISWHT(m) ((m & 0170000) == 0160000) /* whiteout */ #endif ... from /usr/include/sys/stat.h % ls -ls /dev ... Device number (major – minor) 0 crw-r----- 2 root operator 116, 0x00010002 Mar 18 2002 ad0 0 crw-r----- 2 root operator 116, 0 Mar 18 2002 ad0a 0 crw-r----- 2 root operator 116, 1 Mar 18 2002 ad0b 0 crw-r----- 2 root operator 116, 2 Mar 18 2002 ad0c • inode has the major/minor number 0 crw-r----- 2 root operator 116, 3 Mar 18 2002 ad0d 0 crw-r----- 2 root operator 116, 4 Mar 18 2002 ad0e – st_rdev 0 crw-r----- 2 root operator 116, 5 Mar 18 2002 ad0f 0 crw-r----- 2 root operator 116, 6 Mar 18 2002 ad0g • major number 0 crw-r----- 2 root operator 116, 7 Mar 18 2002 ad0h ... 0 crw-r----- 2 root operator 13, 8 Mar 18 2002 da1a – identifies the driver 0 crw-r----- 2 root operator 13, 9 Mar 18 2002 da1b ... – used by the kernel to find the driver 0 crw-r----- 1 root kmem 2, 0 Mar 18 2002 mem 0 crw-rw-rw- 1 root wheel 67, 0 Jul 22 2002 meteor0 • minor number 0 crw-rw-rw- 1 root wheel 30, 2 Mar 18 2002 midi0 0 lrwxrwxrwx 1 root wheel 6 Mar 18 2002 mixer -> mixer0 – identifies a sub-unit - disk n, tape n 0 crw-rw-rw- 1 root wheel 30, 0 Mar 18 2002 mixer0 0 lrwxr-xr-x 1 root wheel 8 Mar 20 2002 mouse -> sysmouse – sets some flags/options ... 0 crw-rw-rw- 1 root wheel 2, 12 Mar 18 2002 zero – used by the driver major device number minor device number Major Minor numbers Device Driver • crw-rw-rw- 1 root wheel 2, 2 Apr 17 06:16 /dev/null • crw-r--r-- 1 root wheel 2, 3 Oct 27 17:26 /dev/random • autoconfiguration and initialization • crw-rw-rw- 1 root wheel 2, 12 Oct 27 17:26 /dev/zero • routines to service I/O requests • crw------- 1 root wheel 28, 0 Oct 27 17:26 /dev/ttyd0 – invoked via system call. • crw------- 1 root wheel 28, 1 Oct 27 17:26 /dev/ttyd1 • crw------- 1 root wheel 28, 2 Oct 27 17:26 /dev/ttyd2 – executes synchronously • crw------- 1 root wheel 28, 3 Oct 27 17:26 /dev/ttyd3 – top half of the driver • 0 crw-r----- 2 root operator 116, 0 Oct 27 17:26 /dev/ad0a • interrupt service routines • 0 crw-r----- 2 root operator 116, 1 Oct 27 17:26 /dev/ad0b • 0 crw-r----- 2 root operator 116, 2 Oct 27 17:26 /dev/ad0c – invoked by the hardware fielding an interrupt. • 0 crw-r----- 2 root operator 116, 3 Oct 27 17:26 /dev/ad0d – bottom half of the driver 2
kernel mode trap handler lea 0x5,%eax int $0x80 if (code >= p->p_sysent->sv_size) callp = &p->p_sysent->sv_table[0]; kernel mode the system call else callp = &p->p_sysent->sv_table[code]; handler ... system-call narg = callp->sy_narg & SYF_ARGMASK; user mode ... handler error = (*callp->sy_call)(p, args); int #include <fcntl.h> open(p, uap) #include <sys/joystick.h> struct proc *p; #define DEVJOY "/dev/joy0" register struct open_args /* { ... open the open syscallarg(char *) path; syscallarg(int) flags; main(int cc, char **vv) system-call system call { syscallarg(int) mode; int fd; } */ *uap; handler { if((fd = open(DEVJOY, O_RDONLY)) < 0) { perror(DEVJOY); ... exit(1); return ( spec_open(...)); } special file open from /usr/include/sys/conf.h struct cdevsw { spec_open(ap) d_open_t *d_open; struct vop_open_args /* { d_close_t *d_close; struct vnode *a_vp; d_read_t *d_read; int a_mode; d_write_t *d_write; struct ucred *a_cred; d_ioctl_t *d_ioctl; struct proc *a_p; d_poll_t *d_poll; } */ *ap; d_mmap_t *d_mmap; { d_strategy_t *d_strategy; struct proc *p = ap->a_p; struct vnode *vp = ap->a_vp; const char *d_name; /* base device name, dev_t dev = vp->v_rdev; e.g. 'vn' */ int error; int d_maj; d_dump_t *d_dump; dsw = devsw(dev); d_psize_t *d_psize; u_int d_flags; if ( (dsw == NULL) || (dsw->d_open == NULL)) int d_bmaj; return ENXIO; /* additions below are not binary ... compatible with 4.2 and below */ error = (*dsw->d_open)(dev, ap->a_mode, S_IFCHR, p); d_kqfilter_t *d_kqfilter; }; if (error) return (error); Device driver - sections /* * this file is created by 'mkconf.c' */ int (*bdevsw[])() { • kernel interface: needed for auto-configuration &nulldev, &nulldev, &rkstrategy, &rktab, /* 0 - rk */ &nodev, &nodev, &nodev, 0, /* 1 - rp */ ... – probe/attach 0 }; • user interface int (*cdevsw[])() { &klopen, &klclose, &klread, &klwrite, &klgstty, /* 0 - console */ – open/close &pcopen, &pcclose, &pcread, &pcwrite, &nodev, /* 1 - pc */ &lpopen, &lpclose, &nodev, &lpwrite, &nodev, /* 2 - lp */ ... – read/write &nulldev, &nulldev, &rkread, &rewrite, &nodev, /* 33 - rk */ ... – ioctl 0 }; – poll/select/map 3
Recommend
More recommend