diff --git a/en_US.ISO8859-1/books/arch-handbook/book.sgml b/en_US.ISO8859-1/books/arch-handbook/book.sgml index af9c07821e..6cbec1dd1c 100644 --- a/en_US.ISO8859-1/books/arch-handbook/book.sgml +++ b/en_US.ISO8859-1/books/arch-handbook/book.sgml @@ -1,1101 +1,725 @@ %bookinfo; %chapters; ]> FreeBSD Developers' Handbook The FreeBSD Documentation Project
doc@FreeBSD.org
August 2000 2000 The FreeBSD Documentation Project &bookinfo.legalnotice; Welcome to the Developers' Handbook.
Introduction Developing on FreeBSD This will need to discuss FreeBSD as a development platform, the vision of BSD, architectural overview, layout of /usr/src, history, etc. Thank you for considering FreeBSD as your development platform! We hope it will not let you down. The BSD Vision Architectural Overview The Layout of /usr/src The complete source code to FreeBSD is available from our public CVS repository. The source code is normally installed in /usr/src which contains the following subdirectories. Directory Description bin/ Source for files in /bin contrib/ Source for files from contribued software. crypto/ DES source etc/ Source for files in /etc games/ Source for files in /usr/games gnu/ Utilities covered by the GNU Public License include/ Source for files in /usr/include kerberosIV/ Source for Kerbereros version IV kerberos5/ Source for Kerbereros version 5 lib/ Source for files in /usr/lib libexec/ Source for files in /usr/libexec release/ Files required to produce a FreeBSD release sbin/ Source for files in /sbin secure/ FreeSec sources share/ Source for files in /sbin sys/ Kernel source files tools/ Tools used for maintenance and testing of FreeBSD usr.bin/ Source for files in /usr/bin usr.sbin/ Source for files in /usr/sbin Basics &chap.tools; &chap.secure; Kernel History of the Unix Kernel Some history of the Unix/BSD kernel, system calls, how do processes work, blocking, scheduling, threads (kernel), context switching, signals, interrupts, modules, etc. Memory and Virtual Memory Virtual Memory VM, paging, swapping, allocating memory, testing for memory leaks, mmap, vnodes, etc. I/O System UFS UFS, FFS, Ext2FS, JFS, inodes, buffer cache, labeling, locking, metadata, soft-updates, LFS, portalfs, procfs, vnodes, memory sharing, memory objects, TLBs, caching Interprocess Communication Signals Signals, pipes, semaphores, message queues, shared memory, ports, sockets, doors Networking Sockets Sockets, bpf, IP, TCP, UDP, ICMP, OSI, bridging, firewalling, NAT, switching, etc Network Filesystems AFS AFS, NFS, SANs etc] Terminal Handling Syscons Syscons, tty, PCVT, serial console, screen savers, etc Sound OSS OSS, waveforms, etc Device Drivers - - Writing FreeBSD Device Drivers - - This chapter was written by Murray Stokely with selections from - a variety of sources including the intro(4) man page by Joerg - Wunsch. - - - Introduction - - This chapter provides a brief introduction to writing device - drivers for FreeBSD. A device in this context is a term used - mostly for hardware-related stuff that belongs to the system, - like disks, printers, or a graphics display with its keyboard. - A device driver is the software component of the operating - system that controls a specific device. There are also - so-called pseudo-devices where a device driver emulates the - behaviour of a device in software without any particular - underlying hardware. Device drivers can be compiled into the - system statically or loaded on demand through the dynamic - kernel linker facility `kld'. - - Most devices in a Unix-like operating system are - accessed through device-nodes, sometimes also called special - files. These files are usually located under the directory - /dev in the file system hierarchy. Until - devfs is fully integrated into FreeBSD, each device node must - be created statically and independent of the existence of the - associated device driver. Most device nodes on the system are - created by running MAKEDEV. - - Device drivers can roughly be broken down into three - categories; character (unbuffered), block (buffered), and - network drivers. - - - - Dynamic Kernel Linker Facility - KLD - The kld interface allows system administrators to - dynamically add and remove functionality from a running - system. This allows device driver writers to load their new - changes into a running kernel without constantly rebooting to - test changes. - - The kld interface is used through the following - administrator commands : - - kldload - loads a new kernel - module - kldunload - unloads a kernel - module - kldstat - lists the currently loadded - modules - - - - Skeleton Layout of a kernel module - -/* - * KLD Skeleton - * Inspired by Andrew Reiter's Daemonnews article - */ - -#include <sys/types.h> -#include <sys/module.h> -#include <sys/systm.h> /* uprintf */ -#include <sys/errno.h> -#include <sys/param.h> /* defines used in kernel.h */ -#include <sys/kernel.h> /* types used in module initialization */ - -/* - * Load handler that deals with the loading and unloading of a KLD. - */ - -static int -skel_loader(struct module *m, int what, void *arg) -{ - int err = 0; - - switch (what) { - case MOD_LOAD: /* kldload */ - uprintf("Skeleton KLD loaded.\n"); - break; - case MOD_UNLOAD: - uprintf("Skeleton KLD unloaded.\n"); - break; - default: - err = EINVAL; - break; - } - return(err); -} - -/* Declare this module to the rest of the kernel */ - -DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY); - - - - - Makefile - FreeBSD provides a makefile include that you can use - to quickly compile your kernel addition. - -SRCS=skeleton.c -KMOD=skeleton - -.include <bsd.kmod.mk> - - - - Simply running make with - this makefile will create a file - skeleton.ko that can be loaded into - your system by typing : - -&prompt.root kldload -v ./skeleton.ko - - - - - - - Accessing a device driver - Unix provides a common set of system calls for user - applications to use. The upper layers of the kernel dispatch - these calls to the corresponding device driver when a user - accesses a device node. The /dev/MAKEDEV - script makes most of the device nodes for your system but if - you are doing your own driver development it may be necessary - to create your own device nodes with mknod - - - - Creating static device nodes - The mknod command requires four - arguments to create a device node. You must specify the - name of this device node, the type of device, the major number - of the device, and the minor number of the device. - - - - Dynamic device nodes - The device filesystem, or devfs, provides access to the - kernel's device namespace in the global filesystem namespace. - This eliminates the problems of potentially having a device - driver without a static device node, or a device node without - an installed device driver. Unfortunately, devfs is still a - work in progress. - - - - - - Character Devices - A character device driver is one that transfers data - directly to and from a user process. This is the most common - type of device driver and there are plenty of simple examples - in the source tree. - This simple example pseudo-device remembers whatever values you write - to it and can then supply them back to you when you read from - it. - -/* - * Simple `echo' pseudo-device KLD - * - * Murray Stokely - */ - -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) - -#include <sys/types.h> -#include <sys/module.h> -#include <sys/systm.h> /* uprintf */ -#include <sys/errno.h> -#include <sys/param.h> /* defines used in kernel.h */ -#include <sys/kernel.h> /* types used in module initialization */ -#include <sys/conf.h> /* cdevsw struct */ -#include <sys/uio.h> /* uio struct */ -#include <sys/malloc.h> - -#define BUFFERSIZE 256 - -/* Function prototypes */ -d_open_t echo_open; -d_close_t echo_close; -d_read_t echo_read; -d_write_t echo_write; - -/* Character device entry points */ -static struct cdevsw echo_cdevsw = { - echo_open, - echo_close, - echo_read, - echo_write, - noioctl, - nopoll, - nommap, - nostrategy, - "echo", - 33, /* reserved for lkms - /usr/src/sys/conf/majors */ - nodump, - nopsize, - D_TTY, - -1 -}; - -typedef struct s_echo { - char msg[BUFFERSIZE]; - int len; -} t_echo; - -/* vars */ -static dev_t sdev; -static int len; -static int count; -static t_echo *echomsg; - -MALLOC_DECLARE(M_ECHOBUF); -MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); - -/* - * This function acts is called by the kld[un]load(2) system calls to - * determine what actions to take when a module is loaded or unloaded. - */ - -static int -echo_loader(struct module *m, int what, void *arg) -{ - int err = 0; - - switch (what) { - case MOD_LOAD: /* kldload */ - sdev = make_dev(&echo_cdevsw, - 0, - UID_ROOT, - GID_WHEEL, - 0600, - "echo"); - /* kmalloc memory for use by this driver */ - /* malloc(256,M_ECHOBUF,M_WAITOK); */ - MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK); - printf("Echo device loaded.\n"); - break; - case MOD_UNLOAD: - destroy_dev(sdev); - FREE(echomsg,M_ECHOBUF); - printf("Echo device unloaded.\n"); - break; - default: - err = EINVAL; - break; - } - return(err); -} - -int -echo_open(dev_t dev, int oflags, int devtype, struct proc *p) -{ - int err = 0; - - uprintf("Opened device \"echo\" successfully.\n"); - return(err); -} - -int -echo_close(dev_t dev, int fflag, int devtype, struct proc *p) -{ - uprintf("Closing device \"echo.\"\n"); - return(0); -} - -/* - * The read function just takes the buf that was saved via - * echo_write() and returns it to userland for accessing. - * uio(9) - */ - -int -echo_read(dev_t dev, struct uio *uio, int ioflag) -{ - int err = 0; - int amt; - - /* How big is this read operation? Either as big as the user wants, - or as big as the remaining data */ - amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); - if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) { - uprintf("uiomove failed!\n"); - } - - return err; -} - -/* - * echo_write takes in a character string and saves it - * to buf for later accessing. - */ - -int -echo_write(dev_t dev, struct uio *uio, int ioflag) -{ - int err = 0; - - /* Copy the string in from user memory to kernel memory */ - err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE)); - - /* Now we need to null terminate */ - *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; - /* Record the length */ - echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); - - if (err != 0) { - uprintf("Write failed: bad address!\n"); - } - - count++; - return(err); -} - -DEV_MODULE(echo,echo_loader,NULL); - - -To install this driver you will first need to make a node on - your filesystem with a command such as : - - &prompt.root mknod /dev/echo c 33 0 - -With this driver loaded you should now be able to type something - like : - - &prompt.root echo -n "Test Data" > /dev/echo - &prompt.root cat /dev/echo - Test Data - - Real hardware devices in the next chapter.. - - Additional Resources - - Dynamic - Kernel Linker (KLD) Facility Programming Tutorial - - Daemonnews October 2000 - How - to Write Kernel Drivers with NEWBUS - Daemonnews July - 2000 - - - - - - Block Devices - A block device driver transfers data to and from the - operating system's buffer cache. They are solely intended to - layer a file system on top of them. For this reason they are - normally implemented for disks and disk-like devices only. - - Example test data generator ... - - Example ramdisk device ... - - Real hardware devices in the next chapter.. - - - - Network Drivers - Drivers for network devices do not use device nodes in - ord to be accessed. Their selection is based on other - decisions made inside the kernel and instead of calling - open(), use of a network device is generally introduced by - using the system call socket(2). - man ifnet(), loopback device, Bill Pauls drivers, etc.. - - - + &chap.driverbasics; PCI Devices This chapter will talk about the FreeBSD mechanisms for writing a device driver for a device on a PCI bus. Probe and Attach Information here about how the PCI bus code iterates through the unattached devices and see if a newly loaded kld will attach to any of them. /* * Simple KLD to play with the PCI functions. * * Murray Stokely */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ #include <sys/conf.h> /* cdevsw struct */ #include <sys/uio.h> /* uio struct */ #include <sys/malloc.h> #include <sys/bus.h> /* structs, prototypes for pci bus stuff */ #include <pci/pcivar.h> /* For get_pci macros! */ /* Function prototypes */ d_open_t mypci_open; d_close_t mypci_close; d_read_t mypci_read; d_write_t mypci_write; /* Character device entry points */ static struct cdevsw mypci_cdevsw = { mypci_open, mypci_close, mypci_read, mypci_write, noioctl, nopoll, nommap, nostrategy, "mypci", 36, /* reserved for lkms - /usr/src/sys/conf/majors */ nodump, nopsize, D_TTY, -1 }; /* vars */ static dev_t sdev; /* We're more interested in probe/attach than with open/close/read/write at this point */ int mypci_open(dev_t dev, int oflags, int devtype, struct proc *p) { int err = 0; uprintf("Opened device \"mypci\" successfully.\n"); return(err); } int mypci_close(dev_t dev, int fflag, int devtype, struct proc *p) { int err=0; uprintf("Closing device \"mypci.\"\n"); return(err); } int mypci_read(dev_t dev, struct uio *uio, int ioflag) { int err = 0; uprintf("mypci read!\n"); return err; } int mypci_write(dev_t dev, struct uio *uio, int ioflag) { int err = 0; uprintf("mypci write!\n"); return(err); } /* PCI Support Functions */ /* * Return identification string if this is device is ours. */ static int mypci_probe(device_t dev) { uprintf("MyPCI Probe\n" "Vendor ID : 0x%x\n" "Device ID : 0x%x\n",pci_get_vendor(dev),pci_get_device(dev)); if (pci_get_vendor(dev) == 0x11c1) { uprintf("We've got the Winmodem, probe successful!\n"); return 0; } return ENXIO; } /* Attach function is only called if the probe is successful */ static int mypci_attach(device_t dev) { uprintf("MyPCI Attach for : deviceID : 0x%x\n",pci_get_vendor(dev)); sdev = make_dev(&mypci_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "mypci"); uprintf("Mypci device loaded.\n"); return ENXIO; } /* Detach device. */ static int mypci_detach(device_t dev) { uprintf("Mypci detach!\n"); return 0; } /* Called during system shutdown after sync. */ static int mypci_shutdown(device_t dev) { uprintf("Mypci shutdown!\n"); return 0; } /* * Device suspend routine. */ static int mypci_suspend(device_t dev) { uprintf("Mypci suspend!\n"); return 0; } /* * Device resume routine. */ static int mypci_resume(device_t dev) { uprintf("Mypci resume!\n"); return 0; } static device_method_t mypci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, mypci_probe), DEVMETHOD(device_attach, mypci_attach), DEVMETHOD(device_detach, mypci_detach), DEVMETHOD(device_shutdown, mypci_shutdown), DEVMETHOD(device_suspend, mypci_suspend), DEVMETHOD(device_resume, mypci_resume), { 0, 0 } }; static driver_t mypci_driver = { "mypci", mypci_methods, 0, /* sizeof(struct mypci_softc), */ }; static devclass_t mypci_devclass; DRIVER_MODULE(mypci, pci, mypci_driver, mypci_devclass, 0, 0); Additional Resources PCI Special Interest Group PCI System Architecture, Fourth Edition by Tom Shanley, et al. USB Devices This chapter will talk about the FreeBSD mechanisms for writing a device driver for a device on a USB bus. NewBus This chapter will talk about the FreeBSD NewBus architecture. Architectures IA-32 Talk about the architectural specifics of FreeBSD/x86. Alpha Talk about the architectural specifics of FreeBSD/alpha. Explanation of allignment errors, how to fix, how to ignore. Example assembly language code for FreeBSD/alpha. IA-64 Talk about the architectural specifics of FreeBSD/ia64. Debugging Truss various descriptions on how to debug certain aspects of the system using truss, ktrace, gdb, kgdb, etc Compatibility Layers Linux Linux, SVR4, etc Appendices Dave A Patterson John L Hennessy 1998Morgan Kaufmann Publishers, Inc. 1-55860-428-6 Morgan Kaufmann Publishers, Inc. Computer Organization and Design The Hardware / Software Interface 1-2 W. Richard Stevens 1993Addison Wesley Longman, Inc. 0-201-56317-7 Addison Wesley Longman, Inc. Advanced Programming in the Unix Environment 1-2 Marshall Kirk McKusick Keith Bostic Michael J Karels John S Quarterman 1996Addison-Wesley Publishing Company, Inc. 0-201-54979-4 Addison-Wesley Publishing Company, Inc. The Design and Implementation of the 4.4 BSD Operating System 1-2 Aleph One Phrack 49; "Smashing the Stack for Fun and Profit" Chrispin Cowan Calton Pu Dave Maier StackGuard; Automatic Adaptive Detection and Prevention of Buffer-Overflow Attacks Todd Miller Theo de Raadt strlcpy and strlcat -- consistent, safe string copy and concatenation.
diff --git a/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml b/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml new file mode 100644 index 0000000000..afee34e472 --- /dev/null +++ b/en_US.ISO8859-1/books/arch-handbook/driverbasics/chapter.sgml @@ -0,0 +1,383 @@ + + + + Writing FreeBSD Device Drivers + + This chapter was written by Murray Stokely with selections from + a variety of sources including the intro(4) man page by Joerg + Wunsch. + + + Introduction + + This chapter provides a brief introduction to writing device + drivers for FreeBSD. A device in this context is a term used + mostly for hardware-related stuff that belongs to the system, + like disks, printers, or a graphics display with its keyboard. + A device driver is the software component of the operating + system that controls a specific device. There are also + so-called pseudo-devices where a device driver emulates the + behaviour of a device in software without any particular + underlying hardware. Device drivers can be compiled into the + system statically or loaded on demand through the dynamic + kernel linker facility `kld'. + + Most devices in a Unix-like operating system are + accessed through device-nodes, sometimes also called special + files. These files are usually located under the directory + /dev in the file system hierarchy. Until + devfs is fully integrated into FreeBSD, each device node must + be created statically and independent of the existence of the + associated device driver. Most device nodes on the system are + created by running MAKEDEV. + + Device drivers can roughly be broken down into three + categories; character (unbuffered), block (buffered), and + network drivers. + + + + Dynamic Kernel Linker Facility - KLD + The kld interface allows system administrators to + dynamically add and remove functionality from a running + system. This allows device driver writers to load their new + changes into a running kernel without constantly rebooting to + test changes. + + The kld interface is used through the following + administrator commands : + + kldload - loads a new kernel + module + kldunload - unloads a kernel + module + kldstat - lists the currently loadded + modules + + + + Skeleton Layout of a kernel module + +/* + * KLD Skeleton + * Inspired by Andrew Reiter's Daemonnews article + */ + +#include <sys/types.h> +#include <sys/module.h> +#include <sys/systm.h> /* uprintf */ +#include <sys/errno.h> +#include <sys/param.h> /* defines used in kernel.h */ +#include <sys/kernel.h> /* types used in module initialization */ + +/* + * Load handler that deals with the loading and unloading of a KLD. + */ + +static int +skel_loader(struct module *m, int what, void *arg) +{ + int err = 0; + + switch (what) { + case MOD_LOAD: /* kldload */ + uprintf("Skeleton KLD loaded.\n"); + break; + case MOD_UNLOAD: + uprintf("Skeleton KLD unloaded.\n"); + break; + default: + err = EINVAL; + break; + } + return(err); +} + +/* Declare this module to the rest of the kernel */ + +DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY); + + + + + Makefile + FreeBSD provides a makefile include that you can use + to quickly compile your kernel addition. + +SRCS=skeleton.c +KMOD=skeleton + +.include <bsd.kmod.mk> + + + + Simply running make with + this makefile will create a file + skeleton.ko that can be loaded into + your system by typing : + +&prompt.root kldload -v ./skeleton.ko + + + + + + + Accessing a device driver + Unix provides a common set of system calls for user + applications to use. The upper layers of the kernel dispatch + these calls to the corresponding device driver when a user + accesses a device node. The /dev/MAKEDEV + script makes most of the device nodes for your system but if + you are doing your own driver development it may be necessary + to create your own device nodes with mknod + + + + Creating static device nodes + The mknod command requires four + arguments to create a device node. You must specify the + name of this device node, the type of device, the major number + of the device, and the minor number of the device. + + + + Dynamic device nodes + The device filesystem, or devfs, provides access to the + kernel's device namespace in the global filesystem namespace. + This eliminates the problems of potentially having a device + driver without a static device node, or a device node without + an installed device driver. Unfortunately, devfs is still a + work in progress. + + + + + + Character Devices + A character device driver is one that transfers data + directly to and from a user process. This is the most common + type of device driver and there are plenty of simple examples + in the source tree. + This simple example pseudo-device remembers whatever values you write + to it and can then supply them back to you when you read from + it. + +/* + * Simple `echo' pseudo-device KLD + * + * Murray Stokely + */ + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#include <sys/types.h> +#include <sys/module.h> +#include <sys/systm.h> /* uprintf */ +#include <sys/errno.h> +#include <sys/param.h> /* defines used in kernel.h */ +#include <sys/kernel.h> /* types used in module initialization */ +#include <sys/conf.h> /* cdevsw struct */ +#include <sys/uio.h> /* uio struct */ +#include <sys/malloc.h> + +#define BUFFERSIZE 256 + +/* Function prototypes */ +d_open_t echo_open; +d_close_t echo_close; +d_read_t echo_read; +d_write_t echo_write; + +/* Character device entry points */ +static struct cdevsw echo_cdevsw = { + echo_open, + echo_close, + echo_read, + echo_write, + noioctl, + nopoll, + nommap, + nostrategy, + "echo", + 33, /* reserved for lkms - /usr/src/sys/conf/majors */ + nodump, + nopsize, + D_TTY, + -1 +}; + +typedef struct s_echo { + char msg[BUFFERSIZE]; + int len; +} t_echo; + +/* vars */ +static dev_t sdev; +static int len; +static int count; +static t_echo *echomsg; + +MALLOC_DECLARE(M_ECHOBUF); +MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); + +/* + * This function acts is called by the kld[un]load(2) system calls to + * determine what actions to take when a module is loaded or unloaded. + */ + +static int +echo_loader(struct module *m, int what, void *arg) +{ + int err = 0; + + switch (what) { + case MOD_LOAD: /* kldload */ + sdev = make_dev(&echo_cdevsw, + 0, + UID_ROOT, + GID_WHEEL, + 0600, + "echo"); + /* kmalloc memory for use by this driver */ + /* malloc(256,M_ECHOBUF,M_WAITOK); */ + MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK); + printf("Echo device loaded.\n"); + break; + case MOD_UNLOAD: + destroy_dev(sdev); + FREE(echomsg,M_ECHOBUF); + printf("Echo device unloaded.\n"); + break; + default: + err = EINVAL; + break; + } + return(err); +} + +int +echo_open(dev_t dev, int oflags, int devtype, struct proc *p) +{ + int err = 0; + + uprintf("Opened device \"echo\" successfully.\n"); + return(err); +} + +int +echo_close(dev_t dev, int fflag, int devtype, struct proc *p) +{ + uprintf("Closing device \"echo.\"\n"); + return(0); +} + +/* + * The read function just takes the buf that was saved via + * echo_write() and returns it to userland for accessing. + * uio(9) + */ + +int +echo_read(dev_t dev, struct uio *uio, int ioflag) +{ + int err = 0; + int amt; + + /* How big is this read operation? Either as big as the user wants, + or as big as the remaining data */ + amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); + if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) { + uprintf("uiomove failed!\n"); + } + + return err; +} + +/* + * echo_write takes in a character string and saves it + * to buf for later accessing. + */ + +int +echo_write(dev_t dev, struct uio *uio, int ioflag) +{ + int err = 0; + + /* Copy the string in from user memory to kernel memory */ + err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE)); + + /* Now we need to null terminate */ + *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; + /* Record the length */ + echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); + + if (err != 0) { + uprintf("Write failed: bad address!\n"); + } + + count++; + return(err); +} + +DEV_MODULE(echo,echo_loader,NULL); + + +To install this driver you will first need to make a node on + your filesystem with a command such as : + + &prompt.root mknod /dev/echo c 33 0 + +With this driver loaded you should now be able to type something + like : + + &prompt.root echo -n "Test Data" > /dev/echo + &prompt.root cat /dev/echo + Test Data + + Real hardware devices in the next chapter.. + + Additional Resources + + Dynamic + Kernel Linker (KLD) Facility Programming Tutorial - + Daemonnews October 2000 + How + to Write Kernel Drivers with NEWBUS - Daemonnews July + 2000 + + + + + + Block Devices + A block device driver transfers data to and from the + operating system's buffer cache. They are solely intended to + layer a file system on top of them. For this reason they are + normally implemented for disks and disk-like devices only. + + Example test data generator ... + + Example ramdisk device ... + + Real hardware devices in the next chapter.. + + + + Network Drivers + Drivers for network devices do not use device nodes in + ord to be accessed. Their selection is based on other + decisions made inside the kernel and instead of calling + open(), use of a network device is generally introduced by + using the system call socket(2). + man ifnet(), loopback device, Bill Pauls drivers, etc.. + + + diff --git a/en_US.ISO8859-1/books/developers-handbook/book.sgml b/en_US.ISO8859-1/books/developers-handbook/book.sgml index af9c07821e..6cbec1dd1c 100644 --- a/en_US.ISO8859-1/books/developers-handbook/book.sgml +++ b/en_US.ISO8859-1/books/developers-handbook/book.sgml @@ -1,1101 +1,725 @@ %bookinfo; %chapters; ]> FreeBSD Developers' Handbook The FreeBSD Documentation Project
doc@FreeBSD.org
August 2000 2000 The FreeBSD Documentation Project &bookinfo.legalnotice; Welcome to the Developers' Handbook.
Introduction Developing on FreeBSD This will need to discuss FreeBSD as a development platform, the vision of BSD, architectural overview, layout of /usr/src, history, etc. Thank you for considering FreeBSD as your development platform! We hope it will not let you down. The BSD Vision Architectural Overview The Layout of /usr/src The complete source code to FreeBSD is available from our public CVS repository. The source code is normally installed in /usr/src which contains the following subdirectories. Directory Description bin/ Source for files in /bin contrib/ Source for files from contribued software. crypto/ DES source etc/ Source for files in /etc games/ Source for files in /usr/games gnu/ Utilities covered by the GNU Public License include/ Source for files in /usr/include kerberosIV/ Source for Kerbereros version IV kerberos5/ Source for Kerbereros version 5 lib/ Source for files in /usr/lib libexec/ Source for files in /usr/libexec release/ Files required to produce a FreeBSD release sbin/ Source for files in /sbin secure/ FreeSec sources share/ Source for files in /sbin sys/ Kernel source files tools/ Tools used for maintenance and testing of FreeBSD usr.bin/ Source for files in /usr/bin usr.sbin/ Source for files in /usr/sbin Basics &chap.tools; &chap.secure; Kernel History of the Unix Kernel Some history of the Unix/BSD kernel, system calls, how do processes work, blocking, scheduling, threads (kernel), context switching, signals, interrupts, modules, etc. Memory and Virtual Memory Virtual Memory VM, paging, swapping, allocating memory, testing for memory leaks, mmap, vnodes, etc. I/O System UFS UFS, FFS, Ext2FS, JFS, inodes, buffer cache, labeling, locking, metadata, soft-updates, LFS, portalfs, procfs, vnodes, memory sharing, memory objects, TLBs, caching Interprocess Communication Signals Signals, pipes, semaphores, message queues, shared memory, ports, sockets, doors Networking Sockets Sockets, bpf, IP, TCP, UDP, ICMP, OSI, bridging, firewalling, NAT, switching, etc Network Filesystems AFS AFS, NFS, SANs etc] Terminal Handling Syscons Syscons, tty, PCVT, serial console, screen savers, etc Sound OSS OSS, waveforms, etc Device Drivers - - Writing FreeBSD Device Drivers - - This chapter was written by Murray Stokely with selections from - a variety of sources including the intro(4) man page by Joerg - Wunsch. - - - Introduction - - This chapter provides a brief introduction to writing device - drivers for FreeBSD. A device in this context is a term used - mostly for hardware-related stuff that belongs to the system, - like disks, printers, or a graphics display with its keyboard. - A device driver is the software component of the operating - system that controls a specific device. There are also - so-called pseudo-devices where a device driver emulates the - behaviour of a device in software without any particular - underlying hardware. Device drivers can be compiled into the - system statically or loaded on demand through the dynamic - kernel linker facility `kld'. - - Most devices in a Unix-like operating system are - accessed through device-nodes, sometimes also called special - files. These files are usually located under the directory - /dev in the file system hierarchy. Until - devfs is fully integrated into FreeBSD, each device node must - be created statically and independent of the existence of the - associated device driver. Most device nodes on the system are - created by running MAKEDEV. - - Device drivers can roughly be broken down into three - categories; character (unbuffered), block (buffered), and - network drivers. - - - - Dynamic Kernel Linker Facility - KLD - The kld interface allows system administrators to - dynamically add and remove functionality from a running - system. This allows device driver writers to load their new - changes into a running kernel without constantly rebooting to - test changes. - - The kld interface is used through the following - administrator commands : - - kldload - loads a new kernel - module - kldunload - unloads a kernel - module - kldstat - lists the currently loadded - modules - - - - Skeleton Layout of a kernel module - -/* - * KLD Skeleton - * Inspired by Andrew Reiter's Daemonnews article - */ - -#include <sys/types.h> -#include <sys/module.h> -#include <sys/systm.h> /* uprintf */ -#include <sys/errno.h> -#include <sys/param.h> /* defines used in kernel.h */ -#include <sys/kernel.h> /* types used in module initialization */ - -/* - * Load handler that deals with the loading and unloading of a KLD. - */ - -static int -skel_loader(struct module *m, int what, void *arg) -{ - int err = 0; - - switch (what) { - case MOD_LOAD: /* kldload */ - uprintf("Skeleton KLD loaded.\n"); - break; - case MOD_UNLOAD: - uprintf("Skeleton KLD unloaded.\n"); - break; - default: - err = EINVAL; - break; - } - return(err); -} - -/* Declare this module to the rest of the kernel */ - -DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY); - - - - - Makefile - FreeBSD provides a makefile include that you can use - to quickly compile your kernel addition. - -SRCS=skeleton.c -KMOD=skeleton - -.include <bsd.kmod.mk> - - - - Simply running make with - this makefile will create a file - skeleton.ko that can be loaded into - your system by typing : - -&prompt.root kldload -v ./skeleton.ko - - - - - - - Accessing a device driver - Unix provides a common set of system calls for user - applications to use. The upper layers of the kernel dispatch - these calls to the corresponding device driver when a user - accesses a device node. The /dev/MAKEDEV - script makes most of the device nodes for your system but if - you are doing your own driver development it may be necessary - to create your own device nodes with mknod - - - - Creating static device nodes - The mknod command requires four - arguments to create a device node. You must specify the - name of this device node, the type of device, the major number - of the device, and the minor number of the device. - - - - Dynamic device nodes - The device filesystem, or devfs, provides access to the - kernel's device namespace in the global filesystem namespace. - This eliminates the problems of potentially having a device - driver without a static device node, or a device node without - an installed device driver. Unfortunately, devfs is still a - work in progress. - - - - - - Character Devices - A character device driver is one that transfers data - directly to and from a user process. This is the most common - type of device driver and there are plenty of simple examples - in the source tree. - This simple example pseudo-device remembers whatever values you write - to it and can then supply them back to you when you read from - it. - -/* - * Simple `echo' pseudo-device KLD - * - * Murray Stokely - */ - -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) - -#include <sys/types.h> -#include <sys/module.h> -#include <sys/systm.h> /* uprintf */ -#include <sys/errno.h> -#include <sys/param.h> /* defines used in kernel.h */ -#include <sys/kernel.h> /* types used in module initialization */ -#include <sys/conf.h> /* cdevsw struct */ -#include <sys/uio.h> /* uio struct */ -#include <sys/malloc.h> - -#define BUFFERSIZE 256 - -/* Function prototypes */ -d_open_t echo_open; -d_close_t echo_close; -d_read_t echo_read; -d_write_t echo_write; - -/* Character device entry points */ -static struct cdevsw echo_cdevsw = { - echo_open, - echo_close, - echo_read, - echo_write, - noioctl, - nopoll, - nommap, - nostrategy, - "echo", - 33, /* reserved for lkms - /usr/src/sys/conf/majors */ - nodump, - nopsize, - D_TTY, - -1 -}; - -typedef struct s_echo { - char msg[BUFFERSIZE]; - int len; -} t_echo; - -/* vars */ -static dev_t sdev; -static int len; -static int count; -static t_echo *echomsg; - -MALLOC_DECLARE(M_ECHOBUF); -MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); - -/* - * This function acts is called by the kld[un]load(2) system calls to - * determine what actions to take when a module is loaded or unloaded. - */ - -static int -echo_loader(struct module *m, int what, void *arg) -{ - int err = 0; - - switch (what) { - case MOD_LOAD: /* kldload */ - sdev = make_dev(&echo_cdevsw, - 0, - UID_ROOT, - GID_WHEEL, - 0600, - "echo"); - /* kmalloc memory for use by this driver */ - /* malloc(256,M_ECHOBUF,M_WAITOK); */ - MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK); - printf("Echo device loaded.\n"); - break; - case MOD_UNLOAD: - destroy_dev(sdev); - FREE(echomsg,M_ECHOBUF); - printf("Echo device unloaded.\n"); - break; - default: - err = EINVAL; - break; - } - return(err); -} - -int -echo_open(dev_t dev, int oflags, int devtype, struct proc *p) -{ - int err = 0; - - uprintf("Opened device \"echo\" successfully.\n"); - return(err); -} - -int -echo_close(dev_t dev, int fflag, int devtype, struct proc *p) -{ - uprintf("Closing device \"echo.\"\n"); - return(0); -} - -/* - * The read function just takes the buf that was saved via - * echo_write() and returns it to userland for accessing. - * uio(9) - */ - -int -echo_read(dev_t dev, struct uio *uio, int ioflag) -{ - int err = 0; - int amt; - - /* How big is this read operation? Either as big as the user wants, - or as big as the remaining data */ - amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); - if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) { - uprintf("uiomove failed!\n"); - } - - return err; -} - -/* - * echo_write takes in a character string and saves it - * to buf for later accessing. - */ - -int -echo_write(dev_t dev, struct uio *uio, int ioflag) -{ - int err = 0; - - /* Copy the string in from user memory to kernel memory */ - err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE)); - - /* Now we need to null terminate */ - *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; - /* Record the length */ - echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); - - if (err != 0) { - uprintf("Write failed: bad address!\n"); - } - - count++; - return(err); -} - -DEV_MODULE(echo,echo_loader,NULL); - - -To install this driver you will first need to make a node on - your filesystem with a command such as : - - &prompt.root mknod /dev/echo c 33 0 - -With this driver loaded you should now be able to type something - like : - - &prompt.root echo -n "Test Data" > /dev/echo - &prompt.root cat /dev/echo - Test Data - - Real hardware devices in the next chapter.. - - Additional Resources - - Dynamic - Kernel Linker (KLD) Facility Programming Tutorial - - Daemonnews October 2000 - How - to Write Kernel Drivers with NEWBUS - Daemonnews July - 2000 - - - - - - Block Devices - A block device driver transfers data to and from the - operating system's buffer cache. They are solely intended to - layer a file system on top of them. For this reason they are - normally implemented for disks and disk-like devices only. - - Example test data generator ... - - Example ramdisk device ... - - Real hardware devices in the next chapter.. - - - - Network Drivers - Drivers for network devices do not use device nodes in - ord to be accessed. Their selection is based on other - decisions made inside the kernel and instead of calling - open(), use of a network device is generally introduced by - using the system call socket(2). - man ifnet(), loopback device, Bill Pauls drivers, etc.. - - - + &chap.driverbasics; PCI Devices This chapter will talk about the FreeBSD mechanisms for writing a device driver for a device on a PCI bus. Probe and Attach Information here about how the PCI bus code iterates through the unattached devices and see if a newly loaded kld will attach to any of them. /* * Simple KLD to play with the PCI functions. * * Murray Stokely */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ #include <sys/conf.h> /* cdevsw struct */ #include <sys/uio.h> /* uio struct */ #include <sys/malloc.h> #include <sys/bus.h> /* structs, prototypes for pci bus stuff */ #include <pci/pcivar.h> /* For get_pci macros! */ /* Function prototypes */ d_open_t mypci_open; d_close_t mypci_close; d_read_t mypci_read; d_write_t mypci_write; /* Character device entry points */ static struct cdevsw mypci_cdevsw = { mypci_open, mypci_close, mypci_read, mypci_write, noioctl, nopoll, nommap, nostrategy, "mypci", 36, /* reserved for lkms - /usr/src/sys/conf/majors */ nodump, nopsize, D_TTY, -1 }; /* vars */ static dev_t sdev; /* We're more interested in probe/attach than with open/close/read/write at this point */ int mypci_open(dev_t dev, int oflags, int devtype, struct proc *p) { int err = 0; uprintf("Opened device \"mypci\" successfully.\n"); return(err); } int mypci_close(dev_t dev, int fflag, int devtype, struct proc *p) { int err=0; uprintf("Closing device \"mypci.\"\n"); return(err); } int mypci_read(dev_t dev, struct uio *uio, int ioflag) { int err = 0; uprintf("mypci read!\n"); return err; } int mypci_write(dev_t dev, struct uio *uio, int ioflag) { int err = 0; uprintf("mypci write!\n"); return(err); } /* PCI Support Functions */ /* * Return identification string if this is device is ours. */ static int mypci_probe(device_t dev) { uprintf("MyPCI Probe\n" "Vendor ID : 0x%x\n" "Device ID : 0x%x\n",pci_get_vendor(dev),pci_get_device(dev)); if (pci_get_vendor(dev) == 0x11c1) { uprintf("We've got the Winmodem, probe successful!\n"); return 0; } return ENXIO; } /* Attach function is only called if the probe is successful */ static int mypci_attach(device_t dev) { uprintf("MyPCI Attach for : deviceID : 0x%x\n",pci_get_vendor(dev)); sdev = make_dev(&mypci_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "mypci"); uprintf("Mypci device loaded.\n"); return ENXIO; } /* Detach device. */ static int mypci_detach(device_t dev) { uprintf("Mypci detach!\n"); return 0; } /* Called during system shutdown after sync. */ static int mypci_shutdown(device_t dev) { uprintf("Mypci shutdown!\n"); return 0; } /* * Device suspend routine. */ static int mypci_suspend(device_t dev) { uprintf("Mypci suspend!\n"); return 0; } /* * Device resume routine. */ static int mypci_resume(device_t dev) { uprintf("Mypci resume!\n"); return 0; } static device_method_t mypci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, mypci_probe), DEVMETHOD(device_attach, mypci_attach), DEVMETHOD(device_detach, mypci_detach), DEVMETHOD(device_shutdown, mypci_shutdown), DEVMETHOD(device_suspend, mypci_suspend), DEVMETHOD(device_resume, mypci_resume), { 0, 0 } }; static driver_t mypci_driver = { "mypci", mypci_methods, 0, /* sizeof(struct mypci_softc), */ }; static devclass_t mypci_devclass; DRIVER_MODULE(mypci, pci, mypci_driver, mypci_devclass, 0, 0); Additional Resources PCI Special Interest Group PCI System Architecture, Fourth Edition by Tom Shanley, et al. USB Devices This chapter will talk about the FreeBSD mechanisms for writing a device driver for a device on a USB bus. NewBus This chapter will talk about the FreeBSD NewBus architecture. Architectures IA-32 Talk about the architectural specifics of FreeBSD/x86. Alpha Talk about the architectural specifics of FreeBSD/alpha. Explanation of allignment errors, how to fix, how to ignore. Example assembly language code for FreeBSD/alpha. IA-64 Talk about the architectural specifics of FreeBSD/ia64. Debugging Truss various descriptions on how to debug certain aspects of the system using truss, ktrace, gdb, kgdb, etc Compatibility Layers Linux Linux, SVR4, etc Appendices Dave A Patterson John L Hennessy 1998Morgan Kaufmann Publishers, Inc. 1-55860-428-6 Morgan Kaufmann Publishers, Inc. Computer Organization and Design The Hardware / Software Interface 1-2 W. Richard Stevens 1993Addison Wesley Longman, Inc. 0-201-56317-7 Addison Wesley Longman, Inc. Advanced Programming in the Unix Environment 1-2 Marshall Kirk McKusick Keith Bostic Michael J Karels John S Quarterman 1996Addison-Wesley Publishing Company, Inc. 0-201-54979-4 Addison-Wesley Publishing Company, Inc. The Design and Implementation of the 4.4 BSD Operating System 1-2 Aleph One Phrack 49; "Smashing the Stack for Fun and Profit" Chrispin Cowan Calton Pu Dave Maier StackGuard; Automatic Adaptive Detection and Prevention of Buffer-Overflow Attacks Todd Miller Theo de Raadt strlcpy and strlcat -- consistent, safe string copy and concatenation.
diff --git a/en_US.ISO8859-1/books/developers-handbook/driverbasics/chapter.sgml b/en_US.ISO8859-1/books/developers-handbook/driverbasics/chapter.sgml new file mode 100644 index 0000000000..afee34e472 --- /dev/null +++ b/en_US.ISO8859-1/books/developers-handbook/driverbasics/chapter.sgml @@ -0,0 +1,383 @@ + + + + Writing FreeBSD Device Drivers + + This chapter was written by Murray Stokely with selections from + a variety of sources including the intro(4) man page by Joerg + Wunsch. + + + Introduction + + This chapter provides a brief introduction to writing device + drivers for FreeBSD. A device in this context is a term used + mostly for hardware-related stuff that belongs to the system, + like disks, printers, or a graphics display with its keyboard. + A device driver is the software component of the operating + system that controls a specific device. There are also + so-called pseudo-devices where a device driver emulates the + behaviour of a device in software without any particular + underlying hardware. Device drivers can be compiled into the + system statically or loaded on demand through the dynamic + kernel linker facility `kld'. + + Most devices in a Unix-like operating system are + accessed through device-nodes, sometimes also called special + files. These files are usually located under the directory + /dev in the file system hierarchy. Until + devfs is fully integrated into FreeBSD, each device node must + be created statically and independent of the existence of the + associated device driver. Most device nodes on the system are + created by running MAKEDEV. + + Device drivers can roughly be broken down into three + categories; character (unbuffered), block (buffered), and + network drivers. + + + + Dynamic Kernel Linker Facility - KLD + The kld interface allows system administrators to + dynamically add and remove functionality from a running + system. This allows device driver writers to load their new + changes into a running kernel without constantly rebooting to + test changes. + + The kld interface is used through the following + administrator commands : + + kldload - loads a new kernel + module + kldunload - unloads a kernel + module + kldstat - lists the currently loadded + modules + + + + Skeleton Layout of a kernel module + +/* + * KLD Skeleton + * Inspired by Andrew Reiter's Daemonnews article + */ + +#include <sys/types.h> +#include <sys/module.h> +#include <sys/systm.h> /* uprintf */ +#include <sys/errno.h> +#include <sys/param.h> /* defines used in kernel.h */ +#include <sys/kernel.h> /* types used in module initialization */ + +/* + * Load handler that deals with the loading and unloading of a KLD. + */ + +static int +skel_loader(struct module *m, int what, void *arg) +{ + int err = 0; + + switch (what) { + case MOD_LOAD: /* kldload */ + uprintf("Skeleton KLD loaded.\n"); + break; + case MOD_UNLOAD: + uprintf("Skeleton KLD unloaded.\n"); + break; + default: + err = EINVAL; + break; + } + return(err); +} + +/* Declare this module to the rest of the kernel */ + +DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY); + + + + + Makefile + FreeBSD provides a makefile include that you can use + to quickly compile your kernel addition. + +SRCS=skeleton.c +KMOD=skeleton + +.include <bsd.kmod.mk> + + + + Simply running make with + this makefile will create a file + skeleton.ko that can be loaded into + your system by typing : + +&prompt.root kldload -v ./skeleton.ko + + + + + + + Accessing a device driver + Unix provides a common set of system calls for user + applications to use. The upper layers of the kernel dispatch + these calls to the corresponding device driver when a user + accesses a device node. The /dev/MAKEDEV + script makes most of the device nodes for your system but if + you are doing your own driver development it may be necessary + to create your own device nodes with mknod + + + + Creating static device nodes + The mknod command requires four + arguments to create a device node. You must specify the + name of this device node, the type of device, the major number + of the device, and the minor number of the device. + + + + Dynamic device nodes + The device filesystem, or devfs, provides access to the + kernel's device namespace in the global filesystem namespace. + This eliminates the problems of potentially having a device + driver without a static device node, or a device node without + an installed device driver. Unfortunately, devfs is still a + work in progress. + + + + + + Character Devices + A character device driver is one that transfers data + directly to and from a user process. This is the most common + type of device driver and there are plenty of simple examples + in the source tree. + This simple example pseudo-device remembers whatever values you write + to it and can then supply them back to you when you read from + it. + +/* + * Simple `echo' pseudo-device KLD + * + * Murray Stokely + */ + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#include <sys/types.h> +#include <sys/module.h> +#include <sys/systm.h> /* uprintf */ +#include <sys/errno.h> +#include <sys/param.h> /* defines used in kernel.h */ +#include <sys/kernel.h> /* types used in module initialization */ +#include <sys/conf.h> /* cdevsw struct */ +#include <sys/uio.h> /* uio struct */ +#include <sys/malloc.h> + +#define BUFFERSIZE 256 + +/* Function prototypes */ +d_open_t echo_open; +d_close_t echo_close; +d_read_t echo_read; +d_write_t echo_write; + +/* Character device entry points */ +static struct cdevsw echo_cdevsw = { + echo_open, + echo_close, + echo_read, + echo_write, + noioctl, + nopoll, + nommap, + nostrategy, + "echo", + 33, /* reserved for lkms - /usr/src/sys/conf/majors */ + nodump, + nopsize, + D_TTY, + -1 +}; + +typedef struct s_echo { + char msg[BUFFERSIZE]; + int len; +} t_echo; + +/* vars */ +static dev_t sdev; +static int len; +static int count; +static t_echo *echomsg; + +MALLOC_DECLARE(M_ECHOBUF); +MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); + +/* + * This function acts is called by the kld[un]load(2) system calls to + * determine what actions to take when a module is loaded or unloaded. + */ + +static int +echo_loader(struct module *m, int what, void *arg) +{ + int err = 0; + + switch (what) { + case MOD_LOAD: /* kldload */ + sdev = make_dev(&echo_cdevsw, + 0, + UID_ROOT, + GID_WHEEL, + 0600, + "echo"); + /* kmalloc memory for use by this driver */ + /* malloc(256,M_ECHOBUF,M_WAITOK); */ + MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK); + printf("Echo device loaded.\n"); + break; + case MOD_UNLOAD: + destroy_dev(sdev); + FREE(echomsg,M_ECHOBUF); + printf("Echo device unloaded.\n"); + break; + default: + err = EINVAL; + break; + } + return(err); +} + +int +echo_open(dev_t dev, int oflags, int devtype, struct proc *p) +{ + int err = 0; + + uprintf("Opened device \"echo\" successfully.\n"); + return(err); +} + +int +echo_close(dev_t dev, int fflag, int devtype, struct proc *p) +{ + uprintf("Closing device \"echo.\"\n"); + return(0); +} + +/* + * The read function just takes the buf that was saved via + * echo_write() and returns it to userland for accessing. + * uio(9) + */ + +int +echo_read(dev_t dev, struct uio *uio, int ioflag) +{ + int err = 0; + int amt; + + /* How big is this read operation? Either as big as the user wants, + or as big as the remaining data */ + amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); + if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) { + uprintf("uiomove failed!\n"); + } + + return err; +} + +/* + * echo_write takes in a character string and saves it + * to buf for later accessing. + */ + +int +echo_write(dev_t dev, struct uio *uio, int ioflag) +{ + int err = 0; + + /* Copy the string in from user memory to kernel memory */ + err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE)); + + /* Now we need to null terminate */ + *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; + /* Record the length */ + echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); + + if (err != 0) { + uprintf("Write failed: bad address!\n"); + } + + count++; + return(err); +} + +DEV_MODULE(echo,echo_loader,NULL); + + +To install this driver you will first need to make a node on + your filesystem with a command such as : + + &prompt.root mknod /dev/echo c 33 0 + +With this driver loaded you should now be able to type something + like : + + &prompt.root echo -n "Test Data" > /dev/echo + &prompt.root cat /dev/echo + Test Data + + Real hardware devices in the next chapter.. + + Additional Resources + + Dynamic + Kernel Linker (KLD) Facility Programming Tutorial - + Daemonnews October 2000 + How + to Write Kernel Drivers with NEWBUS - Daemonnews July + 2000 + + + + + + Block Devices + A block device driver transfers data to and from the + operating system's buffer cache. They are solely intended to + layer a file system on top of them. For this reason they are + normally implemented for disks and disk-like devices only. + + Example test data generator ... + + Example ramdisk device ... + + Real hardware devices in the next chapter.. + + + + Network Drivers + Drivers for network devices do not use device nodes in + ord to be accessed. Their selection is based on other + decisions made inside the kernel and instead of calling + open(), use of a network device is generally introduced by + using the system call socket(2). + man ifnet(), loopback device, Bill Pauls drivers, etc.. + + + diff --git a/en_US.ISO_8859-1/books/developers-handbook/book.sgml b/en_US.ISO_8859-1/books/developers-handbook/book.sgml index af9c07821e..6cbec1dd1c 100644 --- a/en_US.ISO_8859-1/books/developers-handbook/book.sgml +++ b/en_US.ISO_8859-1/books/developers-handbook/book.sgml @@ -1,1101 +1,725 @@ %bookinfo; %chapters; ]> FreeBSD Developers' Handbook The FreeBSD Documentation Project
doc@FreeBSD.org
August 2000 2000 The FreeBSD Documentation Project &bookinfo.legalnotice; Welcome to the Developers' Handbook.
Introduction Developing on FreeBSD This will need to discuss FreeBSD as a development platform, the vision of BSD, architectural overview, layout of /usr/src, history, etc. Thank you for considering FreeBSD as your development platform! We hope it will not let you down. The BSD Vision Architectural Overview The Layout of /usr/src The complete source code to FreeBSD is available from our public CVS repository. The source code is normally installed in /usr/src which contains the following subdirectories. Directory Description bin/ Source for files in /bin contrib/ Source for files from contribued software. crypto/ DES source etc/ Source for files in /etc games/ Source for files in /usr/games gnu/ Utilities covered by the GNU Public License include/ Source for files in /usr/include kerberosIV/ Source for Kerbereros version IV kerberos5/ Source for Kerbereros version 5 lib/ Source for files in /usr/lib libexec/ Source for files in /usr/libexec release/ Files required to produce a FreeBSD release sbin/ Source for files in /sbin secure/ FreeSec sources share/ Source for files in /sbin sys/ Kernel source files tools/ Tools used for maintenance and testing of FreeBSD usr.bin/ Source for files in /usr/bin usr.sbin/ Source for files in /usr/sbin Basics &chap.tools; &chap.secure; Kernel History of the Unix Kernel Some history of the Unix/BSD kernel, system calls, how do processes work, blocking, scheduling, threads (kernel), context switching, signals, interrupts, modules, etc. Memory and Virtual Memory Virtual Memory VM, paging, swapping, allocating memory, testing for memory leaks, mmap, vnodes, etc. I/O System UFS UFS, FFS, Ext2FS, JFS, inodes, buffer cache, labeling, locking, metadata, soft-updates, LFS, portalfs, procfs, vnodes, memory sharing, memory objects, TLBs, caching Interprocess Communication Signals Signals, pipes, semaphores, message queues, shared memory, ports, sockets, doors Networking Sockets Sockets, bpf, IP, TCP, UDP, ICMP, OSI, bridging, firewalling, NAT, switching, etc Network Filesystems AFS AFS, NFS, SANs etc] Terminal Handling Syscons Syscons, tty, PCVT, serial console, screen savers, etc Sound OSS OSS, waveforms, etc Device Drivers - - Writing FreeBSD Device Drivers - - This chapter was written by Murray Stokely with selections from - a variety of sources including the intro(4) man page by Joerg - Wunsch. - - - Introduction - - This chapter provides a brief introduction to writing device - drivers for FreeBSD. A device in this context is a term used - mostly for hardware-related stuff that belongs to the system, - like disks, printers, or a graphics display with its keyboard. - A device driver is the software component of the operating - system that controls a specific device. There are also - so-called pseudo-devices where a device driver emulates the - behaviour of a device in software without any particular - underlying hardware. Device drivers can be compiled into the - system statically or loaded on demand through the dynamic - kernel linker facility `kld'. - - Most devices in a Unix-like operating system are - accessed through device-nodes, sometimes also called special - files. These files are usually located under the directory - /dev in the file system hierarchy. Until - devfs is fully integrated into FreeBSD, each device node must - be created statically and independent of the existence of the - associated device driver. Most device nodes on the system are - created by running MAKEDEV. - - Device drivers can roughly be broken down into three - categories; character (unbuffered), block (buffered), and - network drivers. - - - - Dynamic Kernel Linker Facility - KLD - The kld interface allows system administrators to - dynamically add and remove functionality from a running - system. This allows device driver writers to load their new - changes into a running kernel without constantly rebooting to - test changes. - - The kld interface is used through the following - administrator commands : - - kldload - loads a new kernel - module - kldunload - unloads a kernel - module - kldstat - lists the currently loadded - modules - - - - Skeleton Layout of a kernel module - -/* - * KLD Skeleton - * Inspired by Andrew Reiter's Daemonnews article - */ - -#include <sys/types.h> -#include <sys/module.h> -#include <sys/systm.h> /* uprintf */ -#include <sys/errno.h> -#include <sys/param.h> /* defines used in kernel.h */ -#include <sys/kernel.h> /* types used in module initialization */ - -/* - * Load handler that deals with the loading and unloading of a KLD. - */ - -static int -skel_loader(struct module *m, int what, void *arg) -{ - int err = 0; - - switch (what) { - case MOD_LOAD: /* kldload */ - uprintf("Skeleton KLD loaded.\n"); - break; - case MOD_UNLOAD: - uprintf("Skeleton KLD unloaded.\n"); - break; - default: - err = EINVAL; - break; - } - return(err); -} - -/* Declare this module to the rest of the kernel */ - -DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY); - - - - - Makefile - FreeBSD provides a makefile include that you can use - to quickly compile your kernel addition. - -SRCS=skeleton.c -KMOD=skeleton - -.include <bsd.kmod.mk> - - - - Simply running make with - this makefile will create a file - skeleton.ko that can be loaded into - your system by typing : - -&prompt.root kldload -v ./skeleton.ko - - - - - - - Accessing a device driver - Unix provides a common set of system calls for user - applications to use. The upper layers of the kernel dispatch - these calls to the corresponding device driver when a user - accesses a device node. The /dev/MAKEDEV - script makes most of the device nodes for your system but if - you are doing your own driver development it may be necessary - to create your own device nodes with mknod - - - - Creating static device nodes - The mknod command requires four - arguments to create a device node. You must specify the - name of this device node, the type of device, the major number - of the device, and the minor number of the device. - - - - Dynamic device nodes - The device filesystem, or devfs, provides access to the - kernel's device namespace in the global filesystem namespace. - This eliminates the problems of potentially having a device - driver without a static device node, or a device node without - an installed device driver. Unfortunately, devfs is still a - work in progress. - - - - - - Character Devices - A character device driver is one that transfers data - directly to and from a user process. This is the most common - type of device driver and there are plenty of simple examples - in the source tree. - This simple example pseudo-device remembers whatever values you write - to it and can then supply them back to you when you read from - it. - -/* - * Simple `echo' pseudo-device KLD - * - * Murray Stokely - */ - -#define MIN(a,b) (((a) < (b)) ? (a) : (b)) - -#include <sys/types.h> -#include <sys/module.h> -#include <sys/systm.h> /* uprintf */ -#include <sys/errno.h> -#include <sys/param.h> /* defines used in kernel.h */ -#include <sys/kernel.h> /* types used in module initialization */ -#include <sys/conf.h> /* cdevsw struct */ -#include <sys/uio.h> /* uio struct */ -#include <sys/malloc.h> - -#define BUFFERSIZE 256 - -/* Function prototypes */ -d_open_t echo_open; -d_close_t echo_close; -d_read_t echo_read; -d_write_t echo_write; - -/* Character device entry points */ -static struct cdevsw echo_cdevsw = { - echo_open, - echo_close, - echo_read, - echo_write, - noioctl, - nopoll, - nommap, - nostrategy, - "echo", - 33, /* reserved for lkms - /usr/src/sys/conf/majors */ - nodump, - nopsize, - D_TTY, - -1 -}; - -typedef struct s_echo { - char msg[BUFFERSIZE]; - int len; -} t_echo; - -/* vars */ -static dev_t sdev; -static int len; -static int count; -static t_echo *echomsg; - -MALLOC_DECLARE(M_ECHOBUF); -MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); - -/* - * This function acts is called by the kld[un]load(2) system calls to - * determine what actions to take when a module is loaded or unloaded. - */ - -static int -echo_loader(struct module *m, int what, void *arg) -{ - int err = 0; - - switch (what) { - case MOD_LOAD: /* kldload */ - sdev = make_dev(&echo_cdevsw, - 0, - UID_ROOT, - GID_WHEEL, - 0600, - "echo"); - /* kmalloc memory for use by this driver */ - /* malloc(256,M_ECHOBUF,M_WAITOK); */ - MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK); - printf("Echo device loaded.\n"); - break; - case MOD_UNLOAD: - destroy_dev(sdev); - FREE(echomsg,M_ECHOBUF); - printf("Echo device unloaded.\n"); - break; - default: - err = EINVAL; - break; - } - return(err); -} - -int -echo_open(dev_t dev, int oflags, int devtype, struct proc *p) -{ - int err = 0; - - uprintf("Opened device \"echo\" successfully.\n"); - return(err); -} - -int -echo_close(dev_t dev, int fflag, int devtype, struct proc *p) -{ - uprintf("Closing device \"echo.\"\n"); - return(0); -} - -/* - * The read function just takes the buf that was saved via - * echo_write() and returns it to userland for accessing. - * uio(9) - */ - -int -echo_read(dev_t dev, struct uio *uio, int ioflag) -{ - int err = 0; - int amt; - - /* How big is this read operation? Either as big as the user wants, - or as big as the remaining data */ - amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); - if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) { - uprintf("uiomove failed!\n"); - } - - return err; -} - -/* - * echo_write takes in a character string and saves it - * to buf for later accessing. - */ - -int -echo_write(dev_t dev, struct uio *uio, int ioflag) -{ - int err = 0; - - /* Copy the string in from user memory to kernel memory */ - err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE)); - - /* Now we need to null terminate */ - *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; - /* Record the length */ - echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); - - if (err != 0) { - uprintf("Write failed: bad address!\n"); - } - - count++; - return(err); -} - -DEV_MODULE(echo,echo_loader,NULL); - - -To install this driver you will first need to make a node on - your filesystem with a command such as : - - &prompt.root mknod /dev/echo c 33 0 - -With this driver loaded you should now be able to type something - like : - - &prompt.root echo -n "Test Data" > /dev/echo - &prompt.root cat /dev/echo - Test Data - - Real hardware devices in the next chapter.. - - Additional Resources - - Dynamic - Kernel Linker (KLD) Facility Programming Tutorial - - Daemonnews October 2000 - How - to Write Kernel Drivers with NEWBUS - Daemonnews July - 2000 - - - - - - Block Devices - A block device driver transfers data to and from the - operating system's buffer cache. They are solely intended to - layer a file system on top of them. For this reason they are - normally implemented for disks and disk-like devices only. - - Example test data generator ... - - Example ramdisk device ... - - Real hardware devices in the next chapter.. - - - - Network Drivers - Drivers for network devices do not use device nodes in - ord to be accessed. Their selection is based on other - decisions made inside the kernel and instead of calling - open(), use of a network device is generally introduced by - using the system call socket(2). - man ifnet(), loopback device, Bill Pauls drivers, etc.. - - - + &chap.driverbasics; PCI Devices This chapter will talk about the FreeBSD mechanisms for writing a device driver for a device on a PCI bus. Probe and Attach Information here about how the PCI bus code iterates through the unattached devices and see if a newly loaded kld will attach to any of them. /* * Simple KLD to play with the PCI functions. * * Murray Stokely */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #include <sys/types.h> #include <sys/module.h> #include <sys/systm.h> /* uprintf */ #include <sys/errno.h> #include <sys/param.h> /* defines used in kernel.h */ #include <sys/kernel.h> /* types used in module initialization */ #include <sys/conf.h> /* cdevsw struct */ #include <sys/uio.h> /* uio struct */ #include <sys/malloc.h> #include <sys/bus.h> /* structs, prototypes for pci bus stuff */ #include <pci/pcivar.h> /* For get_pci macros! */ /* Function prototypes */ d_open_t mypci_open; d_close_t mypci_close; d_read_t mypci_read; d_write_t mypci_write; /* Character device entry points */ static struct cdevsw mypci_cdevsw = { mypci_open, mypci_close, mypci_read, mypci_write, noioctl, nopoll, nommap, nostrategy, "mypci", 36, /* reserved for lkms - /usr/src/sys/conf/majors */ nodump, nopsize, D_TTY, -1 }; /* vars */ static dev_t sdev; /* We're more interested in probe/attach than with open/close/read/write at this point */ int mypci_open(dev_t dev, int oflags, int devtype, struct proc *p) { int err = 0; uprintf("Opened device \"mypci\" successfully.\n"); return(err); } int mypci_close(dev_t dev, int fflag, int devtype, struct proc *p) { int err=0; uprintf("Closing device \"mypci.\"\n"); return(err); } int mypci_read(dev_t dev, struct uio *uio, int ioflag) { int err = 0; uprintf("mypci read!\n"); return err; } int mypci_write(dev_t dev, struct uio *uio, int ioflag) { int err = 0; uprintf("mypci write!\n"); return(err); } /* PCI Support Functions */ /* * Return identification string if this is device is ours. */ static int mypci_probe(device_t dev) { uprintf("MyPCI Probe\n" "Vendor ID : 0x%x\n" "Device ID : 0x%x\n",pci_get_vendor(dev),pci_get_device(dev)); if (pci_get_vendor(dev) == 0x11c1) { uprintf("We've got the Winmodem, probe successful!\n"); return 0; } return ENXIO; } /* Attach function is only called if the probe is successful */ static int mypci_attach(device_t dev) { uprintf("MyPCI Attach for : deviceID : 0x%x\n",pci_get_vendor(dev)); sdev = make_dev(&mypci_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600, "mypci"); uprintf("Mypci device loaded.\n"); return ENXIO; } /* Detach device. */ static int mypci_detach(device_t dev) { uprintf("Mypci detach!\n"); return 0; } /* Called during system shutdown after sync. */ static int mypci_shutdown(device_t dev) { uprintf("Mypci shutdown!\n"); return 0; } /* * Device suspend routine. */ static int mypci_suspend(device_t dev) { uprintf("Mypci suspend!\n"); return 0; } /* * Device resume routine. */ static int mypci_resume(device_t dev) { uprintf("Mypci resume!\n"); return 0; } static device_method_t mypci_methods[] = { /* Device interface */ DEVMETHOD(device_probe, mypci_probe), DEVMETHOD(device_attach, mypci_attach), DEVMETHOD(device_detach, mypci_detach), DEVMETHOD(device_shutdown, mypci_shutdown), DEVMETHOD(device_suspend, mypci_suspend), DEVMETHOD(device_resume, mypci_resume), { 0, 0 } }; static driver_t mypci_driver = { "mypci", mypci_methods, 0, /* sizeof(struct mypci_softc), */ }; static devclass_t mypci_devclass; DRIVER_MODULE(mypci, pci, mypci_driver, mypci_devclass, 0, 0); Additional Resources PCI Special Interest Group PCI System Architecture, Fourth Edition by Tom Shanley, et al. USB Devices This chapter will talk about the FreeBSD mechanisms for writing a device driver for a device on a USB bus. NewBus This chapter will talk about the FreeBSD NewBus architecture. Architectures IA-32 Talk about the architectural specifics of FreeBSD/x86. Alpha Talk about the architectural specifics of FreeBSD/alpha. Explanation of allignment errors, how to fix, how to ignore. Example assembly language code for FreeBSD/alpha. IA-64 Talk about the architectural specifics of FreeBSD/ia64. Debugging Truss various descriptions on how to debug certain aspects of the system using truss, ktrace, gdb, kgdb, etc Compatibility Layers Linux Linux, SVR4, etc Appendices Dave A Patterson John L Hennessy 1998Morgan Kaufmann Publishers, Inc. 1-55860-428-6 Morgan Kaufmann Publishers, Inc. Computer Organization and Design The Hardware / Software Interface 1-2 W. Richard Stevens 1993Addison Wesley Longman, Inc. 0-201-56317-7 Addison Wesley Longman, Inc. Advanced Programming in the Unix Environment 1-2 Marshall Kirk McKusick Keith Bostic Michael J Karels John S Quarterman 1996Addison-Wesley Publishing Company, Inc. 0-201-54979-4 Addison-Wesley Publishing Company, Inc. The Design and Implementation of the 4.4 BSD Operating System 1-2 Aleph One Phrack 49; "Smashing the Stack for Fun and Profit" Chrispin Cowan Calton Pu Dave Maier StackGuard; Automatic Adaptive Detection and Prevention of Buffer-Overflow Attacks Todd Miller Theo de Raadt strlcpy and strlcat -- consistent, safe string copy and concatenation.
diff --git a/en_US.ISO_8859-1/books/developers-handbook/driverbasics/chapter.sgml b/en_US.ISO_8859-1/books/developers-handbook/driverbasics/chapter.sgml new file mode 100644 index 0000000000..afee34e472 --- /dev/null +++ b/en_US.ISO_8859-1/books/developers-handbook/driverbasics/chapter.sgml @@ -0,0 +1,383 @@ + + + + Writing FreeBSD Device Drivers + + This chapter was written by Murray Stokely with selections from + a variety of sources including the intro(4) man page by Joerg + Wunsch. + + + Introduction + + This chapter provides a brief introduction to writing device + drivers for FreeBSD. A device in this context is a term used + mostly for hardware-related stuff that belongs to the system, + like disks, printers, or a graphics display with its keyboard. + A device driver is the software component of the operating + system that controls a specific device. There are also + so-called pseudo-devices where a device driver emulates the + behaviour of a device in software without any particular + underlying hardware. Device drivers can be compiled into the + system statically or loaded on demand through the dynamic + kernel linker facility `kld'. + + Most devices in a Unix-like operating system are + accessed through device-nodes, sometimes also called special + files. These files are usually located under the directory + /dev in the file system hierarchy. Until + devfs is fully integrated into FreeBSD, each device node must + be created statically and independent of the existence of the + associated device driver. Most device nodes on the system are + created by running MAKEDEV. + + Device drivers can roughly be broken down into three + categories; character (unbuffered), block (buffered), and + network drivers. + + + + Dynamic Kernel Linker Facility - KLD + The kld interface allows system administrators to + dynamically add and remove functionality from a running + system. This allows device driver writers to load their new + changes into a running kernel without constantly rebooting to + test changes. + + The kld interface is used through the following + administrator commands : + + kldload - loads a new kernel + module + kldunload - unloads a kernel + module + kldstat - lists the currently loadded + modules + + + + Skeleton Layout of a kernel module + +/* + * KLD Skeleton + * Inspired by Andrew Reiter's Daemonnews article + */ + +#include <sys/types.h> +#include <sys/module.h> +#include <sys/systm.h> /* uprintf */ +#include <sys/errno.h> +#include <sys/param.h> /* defines used in kernel.h */ +#include <sys/kernel.h> /* types used in module initialization */ + +/* + * Load handler that deals with the loading and unloading of a KLD. + */ + +static int +skel_loader(struct module *m, int what, void *arg) +{ + int err = 0; + + switch (what) { + case MOD_LOAD: /* kldload */ + uprintf("Skeleton KLD loaded.\n"); + break; + case MOD_UNLOAD: + uprintf("Skeleton KLD unloaded.\n"); + break; + default: + err = EINVAL; + break; + } + return(err); +} + +/* Declare this module to the rest of the kernel */ + +DECLARE_MODULE(skeleton, skel_loader, SI_SUB_KLD, SI_ORDER_ANY); + + + + + Makefile + FreeBSD provides a makefile include that you can use + to quickly compile your kernel addition. + +SRCS=skeleton.c +KMOD=skeleton + +.include <bsd.kmod.mk> + + + + Simply running make with + this makefile will create a file + skeleton.ko that can be loaded into + your system by typing : + +&prompt.root kldload -v ./skeleton.ko + + + + + + + Accessing a device driver + Unix provides a common set of system calls for user + applications to use. The upper layers of the kernel dispatch + these calls to the corresponding device driver when a user + accesses a device node. The /dev/MAKEDEV + script makes most of the device nodes for your system but if + you are doing your own driver development it may be necessary + to create your own device nodes with mknod + + + + Creating static device nodes + The mknod command requires four + arguments to create a device node. You must specify the + name of this device node, the type of device, the major number + of the device, and the minor number of the device. + + + + Dynamic device nodes + The device filesystem, or devfs, provides access to the + kernel's device namespace in the global filesystem namespace. + This eliminates the problems of potentially having a device + driver without a static device node, or a device node without + an installed device driver. Unfortunately, devfs is still a + work in progress. + + + + + + Character Devices + A character device driver is one that transfers data + directly to and from a user process. This is the most common + type of device driver and there are plenty of simple examples + in the source tree. + This simple example pseudo-device remembers whatever values you write + to it and can then supply them back to you when you read from + it. + +/* + * Simple `echo' pseudo-device KLD + * + * Murray Stokely + */ + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) + +#include <sys/types.h> +#include <sys/module.h> +#include <sys/systm.h> /* uprintf */ +#include <sys/errno.h> +#include <sys/param.h> /* defines used in kernel.h */ +#include <sys/kernel.h> /* types used in module initialization */ +#include <sys/conf.h> /* cdevsw struct */ +#include <sys/uio.h> /* uio struct */ +#include <sys/malloc.h> + +#define BUFFERSIZE 256 + +/* Function prototypes */ +d_open_t echo_open; +d_close_t echo_close; +d_read_t echo_read; +d_write_t echo_write; + +/* Character device entry points */ +static struct cdevsw echo_cdevsw = { + echo_open, + echo_close, + echo_read, + echo_write, + noioctl, + nopoll, + nommap, + nostrategy, + "echo", + 33, /* reserved for lkms - /usr/src/sys/conf/majors */ + nodump, + nopsize, + D_TTY, + -1 +}; + +typedef struct s_echo { + char msg[BUFFERSIZE]; + int len; +} t_echo; + +/* vars */ +static dev_t sdev; +static int len; +static int count; +static t_echo *echomsg; + +MALLOC_DECLARE(M_ECHOBUF); +MALLOC_DEFINE(M_ECHOBUF, "echobuffer", "buffer for echo module"); + +/* + * This function acts is called by the kld[un]load(2) system calls to + * determine what actions to take when a module is loaded or unloaded. + */ + +static int +echo_loader(struct module *m, int what, void *arg) +{ + int err = 0; + + switch (what) { + case MOD_LOAD: /* kldload */ + sdev = make_dev(&echo_cdevsw, + 0, + UID_ROOT, + GID_WHEEL, + 0600, + "echo"); + /* kmalloc memory for use by this driver */ + /* malloc(256,M_ECHOBUF,M_WAITOK); */ + MALLOC(echomsg, t_echo *, sizeof(t_echo), M_ECHOBUF, M_WAITOK); + printf("Echo device loaded.\n"); + break; + case MOD_UNLOAD: + destroy_dev(sdev); + FREE(echomsg,M_ECHOBUF); + printf("Echo device unloaded.\n"); + break; + default: + err = EINVAL; + break; + } + return(err); +} + +int +echo_open(dev_t dev, int oflags, int devtype, struct proc *p) +{ + int err = 0; + + uprintf("Opened device \"echo\" successfully.\n"); + return(err); +} + +int +echo_close(dev_t dev, int fflag, int devtype, struct proc *p) +{ + uprintf("Closing device \"echo.\"\n"); + return(0); +} + +/* + * The read function just takes the buf that was saved via + * echo_write() and returns it to userland for accessing. + * uio(9) + */ + +int +echo_read(dev_t dev, struct uio *uio, int ioflag) +{ + int err = 0; + int amt; + + /* How big is this read operation? Either as big as the user wants, + or as big as the remaining data */ + amt = MIN(uio->uio_resid, (echomsg->len - uio->uio_offset > 0) ? echomsg->len - uio->uio_offset : 0); + if ((err = uiomove(echomsg->msg + uio->uio_offset,amt,uio)) != 0) { + uprintf("uiomove failed!\n"); + } + + return err; +} + +/* + * echo_write takes in a character string and saves it + * to buf for later accessing. + */ + +int +echo_write(dev_t dev, struct uio *uio, int ioflag) +{ + int err = 0; + + /* Copy the string in from user memory to kernel memory */ + err = copyin(uio->uio_iov->iov_base, echomsg->msg, MIN(uio->uio_iov->iov_len,BUFFERSIZE)); + + /* Now we need to null terminate */ + *(echomsg->msg + MIN(uio->uio_iov->iov_len,BUFFERSIZE)) = 0; + /* Record the length */ + echomsg->len = MIN(uio->uio_iov->iov_len,BUFFERSIZE); + + if (err != 0) { + uprintf("Write failed: bad address!\n"); + } + + count++; + return(err); +} + +DEV_MODULE(echo,echo_loader,NULL); + + +To install this driver you will first need to make a node on + your filesystem with a command such as : + + &prompt.root mknod /dev/echo c 33 0 + +With this driver loaded you should now be able to type something + like : + + &prompt.root echo -n "Test Data" > /dev/echo + &prompt.root cat /dev/echo + Test Data + + Real hardware devices in the next chapter.. + + Additional Resources + + Dynamic + Kernel Linker (KLD) Facility Programming Tutorial - + Daemonnews October 2000 + How + to Write Kernel Drivers with NEWBUS - Daemonnews July + 2000 + + + + + + Block Devices + A block device driver transfers data to and from the + operating system's buffer cache. They are solely intended to + layer a file system on top of them. For this reason they are + normally implemented for disks and disk-like devices only. + + Example test data generator ... + + Example ramdisk device ... + + Real hardware devices in the next chapter.. + + + + Network Drivers + Drivers for network devices do not use device nodes in + ord to be accessed. Their selection is based on other + decisions made inside the kernel and instead of calling + open(), use of a network device is generally introduced by + using the system call socket(2). + man ifnet(), loopback device, Bill Pauls drivers, etc.. + + +