首页 Linux Loadable Kernel Modules

Linux Loadable Kernel Modules

举报
开通vip

Linux Loadable Kernel Modules Linux Loadable Kernel Modules (LKM’s) Frédéric Dreier, I3S Thomas Zimmermann, I3S July 2002 2/2 Table of contents A: Aim Of This Document A1 Objective...........................

Linux Loadable Kernel Modules
Linux Loadable Kernel Modules (LKM’s) Frédéric Dreier, I3S Thomas Zimmermann, I3S July 2002 2/2 Table of contents A: Aim Of This Document A1 Objective............................................................................................. 3 A2 Acknowledgement................................................................................. 3 A3 Changes.............................................................................................. 3 B: Introduction B1 Loadable Kernel Modules........................................................................ 4 B2 History of Loadable Kernel Modules ......................................................... 4 B3 Module Types....................................................................................... 4 B4 Loadable vs. Built-in ............................................................................. 5 C: Our First Module C1 Goal ................................................................................................... 6 C2 Hello World Deployment ........................................................................ 6 C3 Explanations ........................................................................................ 7 C4 Variations ............................................................................................ 7 D: Proc File Entry D1 Communicating With Userland................................................................ 10 D2 The /proc Directory............................................................................... 10 D3 A Procfs Example.................................................................................. 10 E: Device Drivers E1 Introduction ........................................................................................ 14 F: System Calls F1 Introduction ........................................................................................ 15 F2 Header Files ........................................................................................ 15 F3 Interception ........................................................................................ 15 G: Conclusion G1 Summary ............................................................................................ 18 H: Annexes H1 References .......................................................................................... 19 3/3 A: Aim Of This Document A1: Objective The aim of this document is to share the results of our research and experiments about Linux Loadable Kernel Modules (LKM’s). Since we are no experts and we first heard about programming LKM’s two months ago, we will not present this paper as a reference but more as a smooth diving into the Linux kernel. We expect that you have some little experience in C programming (very little). We also suppose that you have the kernel header files somewhere in /usr/src. We hope this document will be pleasant and instructive. A2: Acknowledgement We would like to thank everybody who has already published something about LKM’s on the internet, and who those who care about Linux documentation (HOWTO’s, guide, …). A3: Changes Zimmermann First draft 01.07.2002 Dreier Customization 03.07.2002 Zimmermann Corrections 07.07.2002 Dreier Updates 08.07.2002 4/4 B: Introduction B1: Loadable Kernel Modules Linux Loadable Kernel Modules (LKM’s) are the most convenient way to customize the Linux kernel. Instead of modifying the source code and recompiling it, we got the possibility to plug-in little pieces of code, called modules, at runtime. B2: History of Loadable Kernel Modules An operating system kernel provides all the primitive functions to access hardware resources in a reliable way. The kernel should stay small to ensure robustness, but should be adaptive to match all possible different hardware (keep in mind that Linux is portable on a bunch of different platforms). A strict monolithic architecture would be a kernel that is compiled with all needed functions (i.e. drivers). Each time we need new hardware support we would have to recompile the whole Kernel. LKM’s have been introduced in Linux 1.2 (1995). An LKM is a piece of code that we can add and remove from kernel at runtime. It does not require a kernel recompilation or reboot of the operating system. Some People think of LKM’s as outside of the kernel. This is a mistake: LKM’s (when loaded) are very much part of the kernel. Actually, almost everything that makes sense as an LKM has the option of being an LKM. B3: Modules types The kernel offers us several access points to control the hardware through its system call interfaces. We can formally split these services in five families (see fig. B-1). As you can see, the following services are implemented as modules: filesystem, block devices, character devices and network drivers. Very common uses of modules are device drivers. They are used to map standard I/O functions on a specific hardware device. Unix system distinguishes between several device types like character-, block-, network- but also SCSI- or USB- devices. On the other hand we can use modules to customize already defined functions in the kernel. Because modules are part of it, they can interact with the virtual filesystem (‘/proc’ entries) or directly modify system calls. 5/5 B: Definitions fig. B-1: kernel split view Finally, we can influence the execution of all binaries and modify the whole computer: hiding files or processes, tracing users, etc. B4: Loadable vs. Built-in There are a lot of advantages with LKM’s. They save time, because you do not have to recompile your kernel each time you make changes. If your modules are buggy (and they will be) they will probably crash your computer. LKM’s are loaded after the kernel base has been initialized. Therefore it is easier to find the problem. LKM’s save memory too, since they are loaded only when needed. LKM’s are faster to maintain and debug. LKM’s are not slower, by the way, than compiled kernel modules. You cannot use LKM’s for things needed during system startup (like e.g. the disk driver where the root filesystem resides) Process management Memory management Filesystems Device control Networking System Call Interface Concurrency, multicasting Virtual memory Files and dirs, VFS Tty’s and device driver Connectivity Implemented features Kernel subsystem Arch. dependent code Memory manager Filesystem types Character devices Network subsystem Software support IF drivers Block devices CPU Memory Disks & COs Consoles Network devices Hardware Kernel Implemented as modules 6/6 C: Our First Module C1: Goal In following chapter, we will explore the possibilities of LKM’s through some simple examples that you will be able to run without difficulties. We will also explain you, step by step, several thoughts about the underlying kernel mechanisms. We will not cover some obscure aspects of the kernel programming like versioning or multi-processors problems. We give you some references, if you want to step in more advance topics, in the annexes section at the end of this document. Let’s start with the well-known hello world example. C2: Hello World Deployment How can I write a module in less than 5 minutes? Let’s take a look at the following code: #define MODULE #include int init_module() { printk(“Hello, world\n”); return 0; } void cleanup_module() { printk(“Goodbye cruel world\n”); } Table C-1: hello world example Save the code as hello.c and compile it as follows: $ gcc –c hello.c Table C-2: compilation This results in a hello.o file. To link it to the kernel use (as root): # insmod hello.o Table C-3: link module into kernel To see the loaded modules list: # lsmod Table C-4: list modules To remove the module, just type: # rmmod hello Table C-5: remove module To see the output, you have to take a look at the log file: # tail /var/log/messages Table C-6: see output 7/7 C: Our First Module C3: Explanations When a module is loaded into the kernel using insmod, the init_module() function is called. This function is generally used to initialize resources and registrations. It returns 0 if no error has been encountered. The function cleanup_module() is called just before the module is unloaded and cannot fail, therefore it returns void. We have to define MODULE before any imports. It could also be set through the –D option of gcc. Importing linux/module.h is mandatory, too. We use printk(), which works like the printf() function that is not accessible from the kernel. As you can see, the printk() function is not imported: because the module is linked to the kernel, it gets automatically access to all kernel public symbols. printk() is a very useful function for debugging and tracing. Therefore it supports in addition priority symbols that can be concatenated directly to the message: printk(“<2>Goodbye cruel world\n”); /* <0> = high priority, …, <7> = low priority */ printk(KERN_DEBUG “Goodbye cruel world\n”); /* or using constants from linux/kernel.h */ Table C-7: messages priorities The location of the logged message depends on your klogd configuration. Normally, all messages are reported in /var/log/messages, but the highest priority (<0> or KERN_EMERG) is generally displayed on all terminals and on the console. The next priority (<1> or KERN_ALERT) is displayed on the console, too. C4: Variations C4.1: The Code Now we will revisit our first example, using new features. We will also write a Makefile. Table C-8: hello world revisited #include /* contains module definitions */ /* There exists macros to insert documentation in object files MODULE_AUTHOR("John Doe"); MODULE_DESCRIPTION("This module is a demo for our presentation"); MODULE_SUPPORTED_DEVICE("This is not a real driver. Actually, no device is supported"); // we can use a macro to initialize a value through the insmod command // insmod hello2.o anIntValue=300 // static int anIntValue = 100; MODULE_PARM (anIntValue, "i"); MODULE_PARM_DESC (anIntValue, "A dummy value used for our presentation (default 100)"); /* This method is called when the module is loaded */ static int __init my_init(void) { printk ("<1>Hello, world. anIntValue is %i\n", anIntValue); return 0; } /* This method is invoked when the module is unloaded */ static void __exit my_cleanup(void) { printk("<1>Goodbye cruel world\n"); } /* define init and cleanup methods */ module_init(my_init); module_exit(my_cleanup); 8/8 C: Our First Module Our small Makefile: INCLUDEDIR = /usr/include CFLAG = -D__KERNEL__ -DMODULE -O -Wall -I$(INCLUDEDIR) all: hello2.o hello2.o: hello2.c gcc $(CFLAG) -c -o $@ $< Table C-9: makefile As already announced, we introduce new macros, which make the code look slightly different. C4.2: Module Description We add a useful module description that is saved in the module object file (MODULE_AUTHOR, MODULE_DESCRIPTION, MODULE_SUPPORTED_DEVICE). This description can be viewed with the modinfo command. [root@pc-linux hello]# modinfo hello2.o filename: hello2.o description: "This module is a demo for our presentation" author: "John Doe" parm: anIntValue int, description "A dummy value used for our show (default 100)" Table C-10: modinfo output C4.3: Passing Parameter We use another macro to pass arguments from the insmod command. MODULE_PARM takes two parameters: the variable to set and its type (“i” for integer, “0-4i” for an array, …). MODULE_PARM_DESC describes the parameter and is optional. C4.4: Built-in Modules If you take a look at the Linux source files (2.2 and later), you will often find the same declarations for the init and the cleanup methods. We use them in our example, too: … static int __init my_init(void) … static void __exit my_cleanup(void) … Table C-11: explicit declarations __init and __exit are macros. You should form a habit of marking the initialization and cleanup functions where appropriated. __init marks initialization code which is thrown away after boot is complete. __exit marks exit code which is not required if the module is built in the kernel. Both have no effect if the LKM is loaded at runtime. It is a way to save some memory for the kernel. C4.5: Explicit Functions To simplify debugging (tracing), it is smart to use personalized function names to initialize and cleanup the module. We can do that using the module_init(my_init) and module_exit(my_cleanup) macros. 9/9 C: Our First Module C4.6: Namespace pollution You can see in our example, that symbols are static. This brings another problematic to our attention: If a module is part of the kernel, then all symbols defined in the module are visible by the rest of the kernel. This can be useful if we want to stack modules together (module using other modules functions). But if this is not the case, it only results in so-called namespace pollution. Old style code sets members as static to prevent this phenomena (static members are not exported by almost all modutils). But more recent kernels provide macros to explicitly hide symbols using the EXPORT_NO_SYMBOLS macro defined in sysdep.h. There is also a mechanism to explicitly export symbols, but we will not dig further into this. [root@pc-linux hello]# cat /proc/ksyms e1aeb060 __insmod_hello_S.text_L56[hello] e1aeb098 __insmod_hello_S.rodata_L41[hello] e1aeb000 __insmod_hello_O/home/john/Documents/school/opsys/modules/… e1ae9060 read_func_foo[proc_example] e1ae94c4 directory [proc_example] e1ae90c8 write_func_foo [proc_example] e1ae94c0 fileOne [proc_example] e1ae9000 __insmod_proc_example_O/home/john/Documents/school/opsys/ … e1ae9060 __insmod_proc_example_S.text_L380 Table C-12: ksym output C4.7: Makefile We do not define MODULE in our source file anymore, but we use the –DMODULE parameter in the Makefile, which has the same effect. We also use the –O option to properly expand inline functions, because they are widely used in kernel and should be optimized. –Wall is suggested in order show all warnings. Finally, it is mandatory to define the -D__KERNEL__ symbol when compiling kernel code, because some parts of kernel headers are protected with #ifdef __KERNEL__ blocks. 10/10 D: Proc File Entry D1: Communicating with Userland Communication between the kernel and userland is one main task of modules. There are two ways to perform that with LKM’s. We can add an entry in the /proc directory or we can make a driver device, and communicate with it through a normal device file. D2: The /proc Directory The /proc directory is not linked on a physical location on a disk. It is mounted on a data structure in memory that is maintained by the kernel. As a module we can ask the kernel to add an entry that looks like a file but which will, in fact, be mapped on our module. It is really convenient because the user can communicate with such a module using simple terminal commands: $ cat /proc/my_entry … $ echo “blabla” > /proc/my_entry … Table D-1: proc entry I/O D3: A Procfs Example D3.1: The Code #include /* contains module declaration */ #include /* contains all procfs methods signature */ /* some constants used in our module */ #define MODULE_NAME "opsys_seminaries" #define MODULE_VERSION "1.0" /* variables */ struct proc_dir_entry *directory, *fileOne; /* pseudo file entries */ /* Procfs callback method * read is called when someone opens * the file entry in the proc directory * using: cat /proc/our_dir/our_module */ int read_func_foo(char* page, /* buffer where we should write*/ char** start, /* seem to be never used in the kernel */ off_t off, /* where we should start to write */ int count, /* how many character we could write */ int* eof, /* used to signal the end of file */ void* data) /* only used if we have defined our own buffer */ { static int readRecallCnt = 0; int len; MOD_INC_USE_COUNT; len = sprintf(page, "Here are some data that the module could\nreturn to userland.\n \ (recall cnt: %d)\n", readRecallCnt ); *eof = 1; printk("(read_%d)\n",readRecallCnt); readRecallCnt++; MOD_DEC_USE_COUNT; return len; /* return number of bytes returned */ } 11/11 D: Proc File Entry /* Procfs callback method * write is called when someone redirects * data to the file: * using: echo "texttext" > /proc/our_dir/our_module */ int write_func_foo(struct file* file, /* this parameter is usually ignored */ const char* buffer, /* it contains data that is passed to the module (at maximum of possible). buffer is not in kernel memory(ro)! Think about copying it */ unsigned long count, /* says how many bytes should be read */ void* data) /* this parameter could be set to use our own buffer (f.e.: using a method for many files */ { static int writeRecallCnt = 0; MOD_INC_USE_COUNT; printk("receive %ld chars (write_%d).\n", count, writeRecallCnt); writeRecallCnt++; MOD_DEC_USE_COUNT; return count; /* return how many chars we have consumed, or * we will receive them again... * WARNING returning a to big count could crash the module! */ } /* This method is invoked when module is loaded */ int __init my_init(void) { /* make a directory in /proc */ directory = proc_mkdir(MODULE_NAME, NULL); if (directory == NULL) goto fail_dir; directory->owner = THIS_MODULE; // mandatory /* make file */ fileOne = create_proc_entry("myProcEntry", 0666, directory); if (fileOne == NULL) goto fail_entry; /* set callback functions on file */ fileOne->read_proc = read_func_foo; fileOne->write_proc = write_func_foo; /* small output */ printk ("Module initialized. Proc entry added.\n"); return 0; fail_entry: printk("<1>ERROR creating myProcEntry"); remove_proc_entry(MODULE_NAME,NULL); /* remove already registered directory */ fail_dir: printk("<1>ERROR creating directory"); return -1; } /* This method is invoked when a module is removed from kernel */ void cleanup_module(void) { // remove pseudo file entry remove_proc_entry("myProcEntry", directory); remove_proc_entry(MODULE_NAME,NULL); // print a small message printk("Module cleanup. Proc entry removed.\n"); } Table D-2: proc_example code 12/12 D: Proc File Entry D3.2: Output [root@pc-linux proc]# insmod proc_example.o [root@pc-linux proc]# echo "What's up?" > /proc/opsys_seminaries/myProcEntry [root@pc-linux proc]# tail /var/log/messages Jul 4 22:42:44 pc-linux kernel: Module initialized. Proc entry added. Jul 4 22:42:49 pc-linux kernel: receive 11 chars (write_0). [root@pc-linux proc]# cat /proc/opsys_seminaries/myProcEntry Here are some data that the module could return to userland. (recall cnt: 2) [root@pc-linux proc]# tail /var/log/messages Jul 4 22:42:44 pc-linux kernel: Module initialized. Proc entry added. Jul 4 22:42:49 pc-linux kernel: receive 11 chars (write_0). Jul 4 22:43:44 pc-linux kernel: (read_0) Jul 4 22:43:44 pc-linux kernel: (read_1)
本文档为【Linux Loadable Kernel Modules】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
is_733603
暂无简介~
格式:pdf
大小:54KB
软件:PDF阅读器
页数:0
分类:
上传时间:2011-04-15
浏览量:11