Linux Kernel Development

12,544 views

Published on

Kernel Development

Published in: Technology
5 Comments
28 Likes
Statistics
Notes
No Downloads
Views
Total views
12,544
On SlideShare
0
From Embeds
0
Number of Embeds
195
Actions
Shares
0
Downloads
0
Comments
5
Likes
28
Embeds 0
No embeds

No notes for slide
  • Linux Kernel Development

    1. 1. Hemen Kapadia 27 th January, 2007 Linux Kernel Development – Character Device Drivers Basics
    2. 2. <ul><li>Device Driver Overview </li></ul><ul><li>Compiling and Booting the Kernel </li></ul><ul><li>Module Development </li></ul><ul><li>Character Device Driver Development </li></ul><ul><li>References </li></ul>
    3. 3. <ul><li>Device Driver Overview </li></ul><ul><ul><li>Device Drivers: Starting Point </li></ul></ul><ul><ul><li>Scope of Device Drivers </li></ul></ul><ul><ul><li>Device Types </li></ul></ul><ul><ul><li>Kernel Subsystems </li></ul></ul>
    4. 4. <ul><li>Device Drivers : Starting Point </li></ul><ul><ul><li>Linux kernel is a large and complex piece of code. </li></ul></ul><ul><ul><li>Kernel newbies are overwhelmed by the complexity. </li></ul></ul><ul><ul><li>Device drives provide a gateway to approach the kernel in a less intimidating manner. </li></ul></ul><ul><ul><li>Device drivers are written as modules, and compiled independently of the kernel. </li></ul></ul><ul><ul><li>Can be plugged to the kernel during runtime depending on requirement of a particular functionality. </li></ul></ul>
    5. 5. <ul><li>Scope of Device Drivers </li></ul><ul><ul><li>Device drivers provide a mechanism rather than dictate a policy. </li></ul></ul><ul><ul><li>Focus on “what capabilities are to be provided” instead of “how the capabilities will be used”. </li></ul></ul><ul><ul><li>For example the floppy driver should only focus on showing the disk as a continuous array of data blocks, it should not focus on checking access permissions etc.. </li></ul></ul><ul><ul><li>Policy decisions can be made at application level. </li></ul></ul><ul><ul><li>However, some policy decisions can be taken. </li></ul></ul>
    6. 6. <ul><li>Device Types </li></ul><ul><ul><li>Linux classifies devices into three classes </li></ul></ul><ul><ul><li>Character Devices </li></ul></ul><ul><ul><li>Can be accessed as a stream of bytes like a file, but unlike files where we can navigate back and forth, character devices are simple data channels that can be accessed sequentially. Example /dev/ttyS0 </li></ul></ul><ul><ul><li>Block Devices </li></ul></ul><ul><ul><li>Devices that usually handle IO operations involving data transfer of one or more whole blocks (usually 512 bytes) are called block devices. Storage devices are usually block devices. Usually have a buffer for requests, to decide on the best way to cater the requests. Ex. /dev/hda </li></ul></ul><ul><ul><li>Network Devices </li></ul></ul><ul><ul><li>These are special devices that provide an interface for exchanging data with other hosts. Usually this is a hardware device but is can also be a pure software interface like the loopback device. Unlike character and block devices, network device does not have mapping in the file system </li></ul></ul>
    7. 7. <ul><li>Kernel Subsystems </li></ul>App1 App2 C Library Actual respective hardware System Call Interface Process Mgmt Memory Mgmt Filesys Mgmt Device Ctrl Networking Filesys Types CPU support code CPU/MMU support code Storage Drivers Character Device Drvr Network Device Drvr
    8. 8. <ul><li>Compiling and Booting </li></ul><ul><ul><li>Kernel Versioning Scheme </li></ul></ul><ul><ul><li>Downloading Source </li></ul></ul><ul><ul><li>Kernel Configuration </li></ul></ul><ul><ul><li>Kernel Compilation </li></ul></ul><ul><ul><li>Kernel Installation and Booting </li></ul></ul>
    9. 9. <ul><li>Kernel Versioning Scheme </li></ul><ul><ul><li>Stable releases </li></ul></ul><ul><ul><ul><li>A stable release every 1 or 2 months </li></ul></ul></ul><ul><ul><ul><li>Examples: 2. 0 .40, 2. 2 .26, 2. 4 .27, </li></ul></ul></ul><ul><ul><ul><li>Stable versions have an even second number. </li></ul></ul></ul><ul><ul><li>Development versions </li></ul></ul><ul><ul><ul><li>Unstable versions used by kernel developers before making a new stable major release </li></ul></ul></ul><ul><ul><ul><li>Examples: 2. 3 .42, 2. 5 .74 </li></ul></ul></ul><ul><ul><ul><li>Development versions have a odd second number. </li></ul></ul></ul>
    10. 10. <ul><li>Downloading Source Code </li></ul><ul><ul><li>All steps to be executed as normal user unless specified. </li></ul></ul><ul><ul><li>Kernel source code can be downloaded from http:// www.kernel.org . </li></ul></ul><ul><ul><li>Source is available as a bzip file (tar.bz2) or a gzip file (tar.gz). </li></ul></ul><ul><ul><li>Extract the source (example commands to extract 2.6.15 source) </li></ul></ul><ul><ul><ul><li>tar jxvf linux-2.6.15.tar.bz2 (in case of bzip file) </li></ul></ul></ul><ul><ul><ul><li>tar zxvf linux-2.6.15.tar.gz (in case of gzip file) </li></ul></ul></ul><ul><ul><li>This will create a directory linux-2.6.15 in the current directory </li></ul></ul><ul><ul><li>Usually the kernel source is located in /usr/src/linux . Do not use this directory to compile your custom kernel. </li></ul></ul><ul><ul><li>Strongly recommended to you use your home directory, so that we can compile the kernel as a normal user and also prevent corruption of any existing kernel source. </li></ul></ul>
    11. 11. <ul><li>Kernel Configuration </li></ul><ul><ul><li>Kernel configuration is the process which defines what features are to be included in the kernel and including mechanism. </li></ul></ul><ul><ul><li>A feature can be configured to be included into the kernel core (inbuilt), to be compiled as a module (to be inserted at runtime) or not to be included at all. </li></ul></ul><ul><ul><li>This generates a file .config in the current directory. </li></ul></ul><ul><ul><li>The xconfig , gconfig and menuconfig utilities provide a graphical menu based configuration mechanism, whereas config does this with an interactive console based dialogue. </li></ul></ul><ul><ul><li>make oldconfig is used to upgrade the .config file from an earlier kernel release. It will issue warning for obsolete symbols and ask new values for new symbols. </li></ul></ul><ul><ul><li>To list all available targets use make help </li></ul></ul>
    12. 12. <ul><li>Kernel Compilation </li></ul><ul><ul><li>To compile the kernel and modules issue make </li></ul></ul><ul><ul><li>To clean the compilation directory of all the built files use make clean . This will not remove the configuration settings of the kernel. </li></ul></ul><ul><ul><li>To clear the configuration settings also issue the command make mrproper . </li></ul></ul><ul><ul><li>After a successful build the following files will be generated. All paths are relative to the kernel compilation directory. </li></ul></ul><ul><ul><ul><li>vmlinux: The raw kernel image, uncompressed. </li></ul></ul></ul><ul><ul><ul><li>arch/<arch-type>/bzImage: Zlib compressed kernel image </li></ul></ul></ul><ul><ul><ul><li>System.map: Kernel symbols mapping address </li></ul></ul></ul>
    13. 13. <ul><li>Installation and Booting (as root) </li></ul><ul><ul><li>In previous step we have successfully compiled the kernel and the modules. Now we need to install and boot the system. </li></ul></ul><ul><ul><li>To install the compiled modules issue make modules_install </li></ul></ul><ul><ul><li>This will copy all modules from the kernel compilation directory to /lib/modules/<kernel version number> </li></ul></ul><ul><ul><li>Next, we need to create the initial ram disk. This can be done as </li></ul></ul><ul><ul><ul><li>mkinitrd –v –f /boot/initrd-<kernel-version>.img <kernel-version> </li></ul></ul></ul><ul><ul><li>Next we need to copy .config, bzImage and System.map from kernel build directory to /boot. </li></ul></ul><ul><ul><ul><li>cp .config /boot/config-<kernel-version> </li></ul></ul></ul><ul><ul><ul><li>cp System.map /boot/System.map-<kernel-version> </li></ul></ul></ul><ul><ul><ul><li>cp arch/i386/boot/bzImage /boot/vmlinuz-<kernel-version> </li></ul></ul></ul>
    14. 14. <ul><li>Installation and Booting (contd.) </li></ul><ul><ul><li>Now we need to update /boot/grub/grub.conf file so as to enable us to boot the system with your customised kernel. </li></ul></ul><ul><ul><li>In case you have lilo as the bootloader, configure /etc/lilo.conf and run lilo. </li></ul></ul><ul><ul><li>Restart the system and select your customised kernel in the bootloader menu for the system to boot. </li></ul></ul>
    15. 15. <ul><li>Module Development </li></ul><ul><ul><li>Introduction to module development </li></ul></ul><ul><ul><li>Module Operations </li></ul></ul><ul><ul><li>Compiling and Loading a module </li></ul></ul><ul><ul><li>The __init and __exit macros </li></ul></ul><ul><ul><li>Licensing and additional information </li></ul></ul><ul><ul><li>Developing a simple module </li></ul></ul>
    16. 16. <ul><li>Introduction to Module Development </li></ul><ul><ul><li>Extend the functionality of the kernel without a need to reboot the system. </li></ul></ul><ul><ul><li>Loaded and unloaded from the kernel on demand. Once loaded they have full access to kernel’s public symbols. </li></ul></ul><ul><ul><li>Help in reducing the size of the kernel. </li></ul></ul><ul><ul><li>Useful to support incompatible drivers (either load one or the other, but not both). </li></ul></ul><ul><ul><li>Useful to deliver binary only drivers without having to rebuild the kernel. </li></ul></ul><ul><ul><li>Modules make it easy to develop drivers without rebooting: load, test, unload, rebuild, load... </li></ul></ul><ul><ul><li>Modules can also be compiled statically into the kernel. </li></ul></ul>
    17. 17. <ul><li>Module Operations </li></ul><ul><ul><li>Modules can be loaded using modprobe or insmod </li></ul></ul><ul><ul><li>Inserted modules can be listed using lsmod </li></ul></ul><ul><ul><li>Modules can be removed using rmmod . </li></ul></ul><ul><ul><li>Licensing and additional information about modules is obtained using modinfo . </li></ul></ul><ul><ul><li>Module dependencies can be obtained using depmod –a <kernel-version> . </li></ul></ul><ul><ul><li>The module dependencies are stored in /lib/modules/<kernel-version>/modules.dep </li></ul></ul><ul><ul><li>The dependencies are automatically computed during kernel build from module exported symbols. The user need not specify any dependencies </li></ul></ul>
    18. 18. <ul><li>Compiling and Loading a module </li></ul><ul><ul><li>Compiling modules is different than compiling user space programs </li></ul></ul><ul><ul><li>Compiling modules is now integrated with Kbuild, the kernel build mechanism </li></ul></ul><ul><ul><li>Kbuild file lists the objects that are to be compiled as modules against obj-m tag </li></ul></ul><ul><ul><li>The Makefile contains the rules to transform the code to a module object </li></ul></ul>
    19. 19. <ul><li>Compiling and Loading a module </li></ul><ul><ul><li>The make syntax for this is (as normal user) </li></ul></ul><ul><ul><ul><li>make –C <kernel build dir> -M `pwd` modules </li></ul></ul></ul><ul><ul><li>For more information refer Documentation/kbuild/modules.txt in kernel source. </li></ul></ul><ul><ul><li>This will create a *.ko file in the working directory. </li></ul></ul><ul><ul><li>It can then be installed as (as root user) </li></ul></ul><ul><ul><ul><li>/sbin/insmod ./<module-name>.ko </li></ul></ul></ul><ul><ul><li>To remove it use command (as root user) </li></ul></ul><ul><ul><ul><li>/sbin/rmmod <module-name> </li></ul></ul></ul>
    20. 20. <ul><li>The __init and __exit macros </li></ul><ul><ul><li>init_module and cleanup_module names are no longer mandatory. </li></ul></ul><ul><ul><li>They can be user defined but need to be specified to the kernel using module_init() and module_exit() macros. </li></ul></ul><ul><ul><li>The __init macro causes the init function to be discarded and its memory freed once the init function finishes. This is applicable for built-in modules, and not for loadable modules. </li></ul></ul><ul><ul><li>The __exit macro causes the omission of the function when the module is built into the kernel, and like __init , has no effect for loadable modules. </li></ul></ul>
    21. 21. <ul><li>Licensing and additional information. </li></ul><ul><ul><li>Mechanism to identify code licensed under the GPL (and other licenses) so people can be warned if the code is non open-source. </li></ul></ul><ul><ul><li>Used by kernel developers to identify issues coming from proprietary drivers. </li></ul></ul><ul><ul><li>Useful for users to check that their system is 100% free. </li></ul></ul><ul><ul><li>Useful for GNU/Linux distributors for their release policy checks. </li></ul></ul><ul><ul><li>This is implemented with MODULE_LICENSE() macro. As of now following license idents are recognised : </li></ul></ul><ul><ul><ul><li>&quot;GPL&quot; [GNU Public License v2 or later] </li></ul></ul></ul><ul><ul><ul><li>&quot;GPL v2&quot; [GNU Public License v2] </li></ul></ul></ul><ul><ul><ul><li>&quot;GPL and additional rights&quot; [GNU Public License v2 rights and more] </li></ul></ul></ul><ul><ul><ul><li>&quot;Dual BSD/GPL&quot; [GNU Public License v2 or BSD license choice] </li></ul></ul></ul><ul><ul><ul><li>&quot;Dual MPL/GPL&quot; [GNU Public License v2 or Mozilla license choice] </li></ul></ul></ul><ul><ul><ul><li>&quot;Proprietary&quot; [Non free products] </li></ul></ul></ul>
    22. 22. <ul><li>Licensing and additional information (contd.) </li></ul><ul><ul><li>Apart from the licensing information additional information can also be provided using the following macros </li></ul></ul><ul><ul><ul><li>MODULE_AUTHOR </li></ul></ul></ul><ul><ul><ul><li>MODULE_DESCRIPTION </li></ul></ul></ul><ul><ul><ul><li>MODULE_VERSION </li></ul></ul></ul><ul><ul><ul><li>MODULE_SUPPORTED_DEVICE </li></ul></ul></ul><ul><ul><li>Most are self explanatory, version string is of the format [<epoch>:]<version>[-<extra-version>] </li></ul></ul><ul><ul><li>The MODULE_SUPPORTED_DEVICE macro might be used in the future to help automatic configuration of modules, but is currently unused other than for documentation purposes. </li></ul></ul>
    23. 23. <ul><li>Character Device Driver Development </li></ul><ul><ul><li>Major and Minor numbers </li></ul></ul><ul><ul><li>User Space and Kernel Space </li></ul></ul><ul><ul><li>User Space and Kernel Space data exchange. </li></ul></ul><ul><ul><li>Character Device Driver Methodology </li></ul></ul><ul><ul><li>Structures used for writing device drivers. </li></ul></ul><ul><ul><li>Registering a Device </li></ul></ul><ul><ul><li>Unregister a Device. </li></ul></ul><ul><ul><li>Issues (try_module_get and module_put) </li></ul></ul><ul><ul><li>Sample Character Device Driver code. </li></ul></ul>
    24. 24. <ul><li>Major and Minor numbers. </li></ul><ul><ul><li>If you issue a “ ls –l /dev ” command you will notice a column of numbers separated by a comma. The first number is called the Major number and the second is called the Minor number. e.g. </li></ul></ul><ul><ul><ul><li>crw-rw-rw- 1 root root 1, 3 Nov 26 21:42 /dev/null </li></ul></ul></ul><ul><ul><li>The Major number tells which driver is used to access the hardware. Each device driver is allocated a number. </li></ul></ul><ul><ul><li>All devices controlled by the same driver have the same Major number. </li></ul></ul><ul><ul><li>The Minor number is used by the device driver to distinguish among the various hardware it controls. </li></ul></ul><ul><ul><li>To see a list of devices registered on the system and the corresponding major numbers issue “ cat /proc/devices ” </li></ul></ul><ul><ul><li>“ mknod ” command is used to create a device file. </li></ul></ul>
    25. 25. <ul><li>Device Types </li></ul><ul><ul><li>Devices are divided into two types: </li></ul></ul><ul><ul><ul><li>Character Devices </li></ul></ul></ul><ul><ul><ul><li>Block Devices </li></ul></ul></ul><ul><ul><li>Block devices have a buffer for requests, so they can decide the best order to cater the requests. Storage devices are mostly block devices. Block devices can perform IO operations in chunks of specific size called block. This block size may vary for different devices. </li></ul></ul><ul><ul><li>Character devices on the other hand can use as many or as few bytes for IO as they need. Most devices are character devices. </li></ul></ul><ul><ul><li>The first character in the output of ls –l command will help us identify if a device is character or block device. In case of character device it is “ c ” whereas for block it is “ b ”. </li></ul></ul><ul><ul><li>“ mknod ” command is used to create a device file. </li></ul></ul>
    26. 26. <ul><li>User Space and Kernel Space. </li></ul>Read buffer Write string read write /dev/foo major/minor User Space Device Driver read handler write handler copy to user copy from user User space needs a device file in /dev to interact with the device through regular file operations (open, read, write etc..) The information of which particular device driver is in charge of device files with a particular major/minor number pair is required by the kernel. Also the kernel would need to have information on which handler functions are to be executed for user space file operations (open, read, write, close) for a given driver
    27. 27. <ul><li>User Space and Kernel space data exchange </li></ul><ul><ul><li>Cannot directly use memcpy between an address in user space and an address in Kernel space as </li></ul></ul><ul><ul><ul><li>They correspond to completely different address space due to virtual memory. </li></ul></ul></ul><ul><ul><ul><li>User space address can be swapped out. </li></ul></ul></ul><ul><ul><li>To achieve this we need to use dedicated functions like </li></ul></ul><ul><ul><ul><li>put_user() </li></ul></ul></ul><ul><ul><ul><li>get_user() </li></ul></ul></ul><ul><ul><ul><li>copy_to_user() </li></ul></ul></ul><ul><ul><ul><li>copy_from_user() </li></ul></ul></ul><ul><ul><li>All these function should return with 0 </li></ul></ul><ul><ul><li>Any other return value is regarded as an error </li></ul></ul>
    28. 28. <ul><li>Character Device Driver Methodology. </li></ul><ul><ul><li>To write a character device driver following operations need to be done </li></ul></ul><ul><ul><ul><li>Register one or a number of device numbers (major/minor) depending on the number of devices to be managed by the driver. </li></ul></ul></ul><ul><ul><ul><li>Register the handler functions that will be called when the user space programs access the device file. </li></ul></ul></ul><ul><ul><ul><li>This is usually done during module initialization. </li></ul></ul></ul><ul><ul><ul><li>Device numbers are assigned by Torben Mathiasen in the kernel development community. Check Documentation/devices.txt in the kernel source directory to find one not yet assigned. However it is a bad practice as it can get assigned in the future. </li></ul></ul></ul><ul><ul><ul><li>Best is to get them registered dynamically, but in that case you cannot make the device file in advance. However this does not cause a hindrance as there are ways to get the dynamically assigned major number. </li></ul></ul></ul>
    29. 29. <ul><li>Structures used for writing device drivers. </li></ul><ul><ul><li>file_operations : used to store pointers to the functions that serve as operation handlers for various user space file operations like open, read etc… </li></ul></ul><ul><ul><li>Not all fields are required. A minimalist set of operations can be achieved by this </li></ul></ul>struct file_operations fops = { .read = device_read, .write = device_write, .open = device_open, .release = device_release };
    30. 30. <ul><li>Structures used for writing device drivers. </li></ul><ul><ul><li>struct file : used to represent each open device in the kernel </li></ul></ul><ul><ul><li>It is created by the kernel in the open system call. </li></ul></ul><ul><ul><li>It is a kernel level structure and never appears at the user space. It should not be confused with FILE, which is a defined by glibc and never appears at kernel level. </li></ul></ul><ul><ul><li>It is usually an argument in the function handlers defined in file_operations structure explained previously. For example: </li></ul></ul>ssize_t (*read) ( struct file *, /* Open file descriptor */ char *, /* Userspace buffer to fill up */ size_t, /* Size of the userspace buffer */ loff_t *); /* Offset in the open file */ Called when userspace reads from the device file.
    31. 31. <ul><li>Registering a character device. </li></ul><ul><ul><li>This is synonymous to assigning a major number to the device during module initialization. </li></ul></ul><ul><ul><li>register_chrdev() is used to assign a major number to the device file. </li></ul></ul><ul><ul><li>In case major is passed as 0, then it dynamically allocates a major number and returns with the same. </li></ul></ul>int register_chrdev( unsigned int major, //req. major number, 0 if dynamic const char *name, //name as in /proc/devices struct file_operations *fops); // operation handlers
    32. 32. <ul><li>Unregister a character device. </li></ul><ul><ul><li>unregister_chrdev() is used to remove a character device. </li></ul></ul><ul><ul><li>We need to pass the device major number and the device name as parameters to this kernel call. </li></ul></ul>int unregister_chrdev( unsigned int major, // device major number const char *name); //name as in /proc/devices
    33. 33. <ul><li>Issues (try_module_get and module_put). </li></ul><ul><ul><li>Cannot allow module to be removed if the corresponding device file in /dev is being accessed by a process. </li></ul></ul><ul><ul><li>Removing the module and a subsequent access from user space will cause a call to the memory location where the corresponding handler function was located. The result is unpredictable in this case. </li></ul></ul><ul><ul><li>cleanup_module returns as void , so cannot help in this situation. </li></ul></ul><ul><ul><li>It is possible to keep track how many processes are using the module. If this number is not 0 then rmmod will fail. </li></ul></ul><ul><ul><li>Implicit checking within cleanup_module . </li></ul></ul><ul><ul><li>Cannot directly modify the counter but can do so using functions </li></ul></ul><ul><ul><ul><li>try_module_get (THIS_MODULE); // Increment </li></ul></ul></ul><ul><ul><ul><li>module_put (THIS_MODULE); // Decrement </li></ul></ul></ul><ul><ul><ul><li>Module_refcount (THIS_MODULE); //Get count </li></ul></ul></ul>
    34. 34. <ul><li>Sample device driver code. </li></ul><ul><ul><li>Prints the dynamically assigned major number in the kernel log. </li></ul></ul><ul><ul><li>The dynamically assigned major number can also be obtained by searching for chardev in / proc/devices . </li></ul></ul><ul><ul><li>Using this major number we need to create a device file in the /dev directory as: </li></ul></ul><ul><ul><ul><li>mknod /dev/chardev c major_number 0 </li></ul></ul></ul><ul><ul><li>Returns number of times the device file was opened when the device is read from </li></ul></ul><ul><ul><ul><li>cat /dev/chardev </li></ul></ul></ul><ul><ul><li>The number of bytes and the string written into the device file is printed in the kernel log. </li></ul></ul><ul><ul><ul><li>echo “hello there” > dev/chardev </li></ul></ul></ul>
    35. 35. <ul><li>References </li></ul><ul><li>Linux Device Drivers 3 rd edition </li></ul><ul><ul><li>http://www.oriley.com/catalog/linuxdrive3 </li></ul></ul><ul><ul><li>Linux Kernel Module Programming Guide </li></ul></ul><ul><ul><li>http://tldp.org/LDP/lkmpg/2.6/html/index.html </li></ul></ul>
    36. 36. Thank You ! Mail: [email_address] Home: http://hemenkapadia.somee.com

    ×