还剩9页未读,继续阅读
本资源只提供10页预览,全部文档请下载后查看!喜欢就下载吧,查找使用更方便
文本内容:
内核模块编程
一、相关原理介绍分析内核模块编程简介
1.1操作系统的内核是单一体系结构的,也就是说,内核是一Linux Monolithic kernel Linux个单独的非常大的程序这种体系结构导致了内核的可扩展性和可维护性比较差,为Linux了弥补单一内核的缺陷,采用了一种全新的机制一一模块编程川模块具有十Linux Module分突出的优点模块本身不被编译入内核映像,这控制了内核的大小;模块一旦被加载,它就和内核中的其它部分完全一样采用了内核模块编程之后,编写设备驱动和修改系统Linux内核变得易于实现因为用户可以根据需要,在不需要对内核进行重新编译的情况下,内核模块可以动态的载入内核或从内核移出改变内核,极大缩短了驱动编写和内核开发的时间内核模块程序结构
1.2Linux一个内核模块主要由如下几个部分组成Linux模块加载函数1通过或命令加载内核模块时,模块的加载函数会自动被内核执行,完insmod modprobe成本模块的相关初始化工作模块卸载函数2当通过命令卸载某模块时,模块的卸载函数会自动被内核执行,完成与模块加载rmmod函数相反的功能模块许可证声明3许可证声明描述内核模块的许可权限,这一部分是必须声明的,如果不声明LICENSE模块被加载时,将收到内核被污染的警告LICENSE,module licenseunspecified taintskernel在内核中,可接受的有、、Linux
2.6LICENSE“GPL”“GPLv2“GPLand additionalrights\Dual、和大多数情况下,内核模块应遵循兼容许可BSD/GPL“Dual MPL/GPL ProprietaryGPLo权其中最常用的许可是和其他可选部分GPL DualBSD/GPL4模块参数,模块参数是模块被加载的时候可以被传递给它的值,它本身对应模块内部的全局变量;模块导出符号,内核模块可以导出符号对应于函数或变量,这样其它模symbol,块可以使用本模块中的变量或函数;模块作者等信息声明内核模块的编译
1.3在内核中,模块的编译需要配置过的内核源代码;编译过程首先回到内核目录Linux
2.6下读取顶层的文件,然后返回模块源码所在目录,经过编译、链接后生成的内核模Makefile块文件的后缀为故内核模块的编译需要自己写文件,当在命令行中执行命ko Makefilemake令时,将调用文件Makefile设计实现内核线程查看
2.1设计一个模块,该模块功能是列出系统中所有内核线程的程序名、号和进程状态该PID内核模块的功能类似于命令只不过该模块专查看内核线程信息首先在文件开始声明一下ps,模块的许可证,即在文件中加入MODULE_LICENSEGPL;根据内核模块编程的模式,一个内核模块应该至少包含两个函数一个初始化函数,还有一个退出干一些收尾清理的工作的函数,当内核模块被卸载时被执行从内核版rmmod本开始,可以为初始化和结束函数起任意的名字在该模块内两个函数分别命名为2313调用宏和static intkernel_thread_initvoidstatic voidkernel_thread_exitvoid module_inito去注册初始化和退出这两个函数,即module_exitmodule_initkernel_thread_init;module_exitkernel_thread_exit;到此内核模块基本框架基本完成为了获取到所有的内核线程,可以使用宏在内核中有内核线程组长链for_each_process0表,每个线程组长通过结构的成员加入该链表中利用可以task_struc tasksfor_each_process访问到链表中的每一个进程具体实现如下struct task_struct*p;for_each_processp〃相关函数及操作对遍历到的每一个线程,读取它的线程号、线程名称以及线程状态并输出当线程状态为时输出为时输出为其他时则输出0runnale,-1unrunnable,stoppedo在这里输出函数并不能使用是用户空间的输出函数,内核空间使用的是printf,printf printk,因为内核没有链接标准的函数库而实际上和的功能类似,是在内核中运C printkprintf printk行的向控制台输出显示的函数日志输出的级别一共有个,由高到低分别为printk8KERN_EMERG0\KERN_ALERT1\KERN_CRIT2\KERN_ERR3\默认KERN_WARNING4KERN_NOTICE5\KERN_INFO6\KERN_DEBUG7,采用的级别是这个默认级别一般为即与DEFAULT.MESSAGE_LOGLEVEL4,在一个级别上KERN_WARNING带参模块的实现
2.2设计一个带参数的模块,参数为进程的号,功能是列出进程的家族信息,包括父进PID程、兄弟进程和子进程的程序名、号PID该模块的基本框架和上一个模块类似,声明模块许可证,注册初始化和结束函数不同之处是在该模块中涉及到了模块参数在操作系统内核中提供了一种模块带参数的机制,Linux是模块的编写者可以在加载模块的时候提供一下信息,这些参数对于模块来说都是一个全局变量定义一个模块参数可通过实现module_parammodule_paramname,type,perm;参数是用户可见的参数名,也是模块中存放模块参数的变量名参数代表参数name type的类型,它可以是、、、等类型最后一个参数制定了模块在文件byte shortint longperm sysfs系统下对应的文件权限,可以使八进制的,也可以是」的定义形式,如S foS_RUGO|S_IWUSR等在该模块中,定义一个进程的作为参数,以实现任意进程家族信息的查询,默认进PID程号为即在不添加参数情况下查看进程号为的进程家族信息,具体实现如下1,1static intpid=l;module_parampid,int,0644;为找到指定的进程,可以使用遍历内核所有进程,查找进程号为PID fojeach.processp的进程找到具体进程后,获取进程的名称接下来判断进程的父进程是否存在,若存在,PID在输出父进程信息ifp-real_parent==NULLprintkNo Parent\n;elseprintkParent:%d%s\n,p-real_parent-pid,p-real_parent-comm;下一步就是该搜索线程号为线程的兄弟进程及子进程在中采用多个链表确保有PID Linux效查找系统里的进程,双向链表内核中广泛的使用因为一般嵌入到啮合数listjiead lisjhead据结构中,为了便于访问链表中的数据,内核提供了一系列的宏来实现链表的常规操作⑵在这里使用和来实现兄弟进程和子进程的查找list_for_each list_entry在上一步中得到了要查找的进程,可以由此进程得到他父进程的所有子进程组成的链表和此进程子进程的链表定义一个结构体用于p-real_parent-children p-children list_heado中list_entrystruct list_head*pp;宏遍历链表,每次list_for_eachpp,p-real_parent-children p-real_parent-children pp指向一个对象成员,而宏进一步得到该对象的指针具体list_entrypp,struct task_struct,sibling;实现兄弟进程和子进程遍历如下struct task_struct*p,*psibling;list_for_eachpp,p-real_parent-childrenpsibling=list_entrypp,struct task_struct,sibling;printknsibling%d%s\nH,psibling-pid,psibling-comm;list_for_eachpp,p-childrenpsibling=list_entrypp,struct task_struct,sibling;printkHchildren%d%s\nH,psibling-pid,psibling-comm;上述过程将输出得到的兄弟进程和子进程的号和进程名称pid文件的编写
2.3Makefile工具最主要也是最基本的功能就是通过文件来描述源程序之Make makefile间的相互关系并自动维护编译工作而文件需要按照某种语法进行编写,文件中需要说makefile明如何编译各个源文件并连接生成可执行文件,并要求定义源文件之间的依赖关系makefile文件是许多编译器-包括下的编译器-维护编译信息的常用方法,只是在集成开发Windows NT环境中,用户通过友好的界面修改文件而已在内核模块编程中,文makefile LinuxMakefile件模版都类似,具体结构如下ifneq$KERNELRELEASE,:=目标文件obj-melseKDIR:=/lib/modules/$shell uname-r/buildPWD:=$shell pwddefault:$MAKE-C$KDIR M=$PWD modulesclean:$MAKE-C$KDIR M=$PWD cleanendif是在内核源码的顶层中定义的一个变量,在第一次读取执行KERNELRELEASE Makefile此时,没有被定义,所以将读取执行之后的内容如Makefile KERNELRELEASEmake else果的目标是直接执行操作,然后结束当的目标为时,指make clean,clean makeall-C$KDIR明跳转到内核源码目录下读取那里的;表明然后返回到当前目录继续读入、Makefile M=$PWD执行当前的当从内核源码目录返回时,已被被定义,此时第一Makefile KERNELRELEASE行的成功,将继续读取之前的内容的内容为语法的语句,指明模ifneq makeelse ifneqkbuild块源码中各文件的依赖关系,以及要生成的目标模块名测试总结内核线程查看测试
3.1切换到内核模块所在路径在命令行中输入得到如下结果:1kernel_threads,make,root@ricky-du-F8Va/home/rickydu/Desktop/duhaiyang/kernelthread#makemake-C/lib/modules/
2.
6.38-8-generic/builcl M=/home/ricky du/Desktop/duhaiyang/k ernelthreadmodulesmake[l]:Entering directory/usr/src/linux-headers-
2.
6.38-8-generic-Building modules,stage
2.MODPOST1modulesmake[l]:Leaving directoryK1root aricky-du-F8Va:/home/rickydu/Desktop/duhaiyang/kernelthread#|输入列出当前目录文件,可以看已生成文件2Is kerneLthreads.koroot@ricky-du-F8Va:/home/rickydu/Desktop/duhaiyang/kernel thread#Is kernelthreads.ckernelthreads.mod.ckernelthreads.o modules.order kernelthreads.ko kernelthreads.mod.oMakefile Module.symversroot@ricky-du-F8Va:/home/rickydu/Desktop/duhaiyang/kernelthread#|⑶用命令载入模块,并用查看模块是否已载入,由下图结果看insmod kerneLthreads.ko Ismod以看到内核已经被载入rMt ricky9V4:/hoee/ricky dn/Deiktop/du^aiyan^/kcrnel threoMISMXIIMule SueVseObykernel threMls124M0blAtvt aisc12131此时在控制台无法看到内核模块输出的信息,可以用查看内核输出信息,可以看到4dmesg内核已经将搜索到的内核线程信息输出
593.818838Kernel threadssearch[
593.810846]
593.810841HAME kthreaddSTATE stopped
593.818843ksoftirqd/8stopped stoppedI
593.818846kworker/ee stopped stopped
593.810850stopped stoppedmigration/e[
593.816857][stopped stoppedmigration/
1593.810860stoppedksoftirqd/
1593.810863]stoppedkworker/O lcpuset[
593.810866]I stopped stoppedkhelper netns
593.818869]stoppedsync supers[
593.816872]stopped stoppedbdi-default[
593.819875]stopped stoppedkintegritydkblockd
593.8198771stopped stoppedkacpidkacpi notify[
593.810880]w stoppedkacpihotplugata sff
593.818883]stopped stoppedkhubdmd[
593.816886]stoppedkworker/1:
1593.818889stoppedkhungtaskd[
593.816892]stoppedkswapdO ksad[
593.810894]stoppedfsnotify markaioI593,816897stoppedecryptfs-kthrea
593.8199601[stoppedcrypto kthrotld
593.818963]stoppedknpathd[
593.816906stoppedkjnpath handlerd
593.819909stoppedkondemandI
593.819912stoppedkconservative593810914stoppedkworker/l:2scsi
593.81G917stoppedeh escsi eh
1593.810926]stopped scsi-eh-
2593.81B9231stopped
593.819926]593,
810929593.816932I
593.819935]
593.
810938593.818946]
593.819944J[593,819947[593,
810956593.
810952333349915689612345678901263593.816938kondemand stopped
593.818940]kconservative stopped
593.81B944kworker/l:2scsieh estopped
593.810947]SC51eh1scsi eh2stoppedstopped
593.810956]scsi eh_3scsi eh4scsistopped stopped
593.819952eh5kworker/u:4stoppedstopped
593.818955J kworker/u:6stopped
593.810958jbd2/sdaie-8stopped
593.810961]ext4-dio-unwritstopped
593.810964kpsiBoused ledstopped
593.819967]workqueue ctgsezustopped
593.8199691r852iwlagn hd-audio8stopped
593.810972hd*audiol
593.81B976]jbd2/sda12-8stopped
593.810979ext4-dio-unwrit stopped
593.819982J jbd2/sda8-8stopped
593.816584ext4-dio-unwrit stopped
593.819987jbd2/sda14-8stopped
593.819990]ext4-dio-unwritstopped
593.816993]jbd2/5dall-8stopped
593.81B996]ext4«dio-unwritstopped[
593.819999]jbd2/sdal3-8stopped
593.811662]ext4-dio-unwritstopped593,811665]flush-8:6firegl fireglstopped
593.811868fireglstopped
593.811011Zeitgeist-datahstopped
593.81iei4kworker/B:2kworker/l estopped
593.811017]kworker/u:6total kernelstopped
593.811620threads593811623stopped
593.811G27]stopped593«811G31]stopped
593.811034]stopped
593.811037]stopped
593.811643]stopped
593.811650]stopped
593.811653]stopped
593.
8118561569593.811G59]最后用命令将已加载的内核卸载5rmmod kernel_threads.ko带参模块的实现测试
3.2⑴切换到内核模块所在路径在命令行中输入得到如下结果:thread_pid,make,root aricky-du-F8Va:/home/ricky_du/Desktop/duhaiyang/thread_pid#makemake[l]:Entering directory/usr/src/linux-headers-
2.
6.38-8-genericBuilding modules,stage
2.MODPOST1modulesmake[l]:Leaving directory/usr/src/linux-headers-
2.
6.38-8-genericroot aricky-du-F8Va:/home/ricky_du/Desktop/duhaiyang/thread_pid#|输入列出当前目录文件,可以看已生成文件21s thread_pid.koroot aricky-du-F8Va:/home/ricky_du/Desktop/duhaiyang/thread_pid#Ismodules.order threadpid.c thread pid.mod.c threadpid.o川root@ricky-du-F8Va:/home/ricky_du/Desktop/duhaiyang/threadpid#⑶用命令载入模块,并用查看模块是否已载入,由下图结果看以看insmod thread_pid.ko Ismod到内核已经被载入2222266688989155^666778882346889538124623B17845453root@ricky-du-F8Va:/home/ricky du/Desktop/duhaiyang/thread pldtismodModule SizeUsed bythreadpid12538ebinfmt misc
132131.此时在控制台无法看到内核模块输出的信息,可以用查看内核输出信息,可以看到4dmesg内核已经将搜索到的内核线程信息输出[
1246.539156]One threadsearch:I
1246.539166Current thread:1init
11246.539172]Parent:G swapper[
1246.539176Sibling1init
11246.539181]Sibling:2kthreadd[
1246.539186]Children:316upstart-udev-br[
1246.539191]Children:333udevd[
1246.539196Children:626upstart-socket-
11246.539201Children814rsyslogd[
1246.539286Children:893getty[
1246.539211]Children:897getty[
1246.539216]Children:909gettyI
1246.539220]Children919getty[
1246.539225]Children:912getty[
1246.539229]Children:913acpidf
1246.539235]Children:907dbus-daemon[
1246.539239Children:971gdm-binary[
1246.539244]Children:972cupsdI
1246.539249]Children:963irqbalance[
1246.539254]Children:935cron[
1246.539258Children:936atd
1246.539263]Children:1621avahi-daemon[
1246.539268]Children:1024Nctwo rkNanager
11246.539273]Children:1936■odem-manager[
1246.539278]Children:1118polkitd
11246.539283]Childrenie38console-kit-dae[
1246.539287]Children1149wpa supplicant
11246.539292]Children:1243getty[
1246.539297]Children:1396ibuSXll
11246.539382]Children:1312dbus-daemon[
1246.539307]Children:1311dbus-daemon
11246.539312Children:1391dbus-launchI
1246.539316]Childrendbus*launchi3ie[
1246.539321]Children:1315gconfd-2[
1246.539326Children:1321gconfd-2[
1246.539331Children1331gnome*keyring-d
1246.539336Children:1337gvf sd[
1246.539348]Children:1342gvfs-fuse-daemo[
1246.539345]Children:1326gnome-settings-[
1246.539359]Children:1358rtkit-daemon[
1246.539326]Children:1321gconfd-2[
1246.539331]Children1331gnome-keynng-d[
1246.539336]Children:1337gvfsd[
1246.539340]Children1342gvfs-fuse-daemo[
1246.539345]Children:1326gnome-settings-[
1246.539359]Children:1358rtkit-daemon[
1246.539355]Children:1376Zeitgeist-daemo[
1246.539360]Children:1389notify-osd[
1246.539364]Children:1393upowerd[
1246.539369Children:1356pulseaudio[
1246.539374]Children1423bonobo-activati[
1246.539379]Children:1488syndaemon[
1246.539383]Children1492gvfsd-trash
11246.539388]Children:1494gnome-screensav[
1246.539393]Children1496udisks-daemon[
1246.539398]Children:1490gvfs-gdu-volume[
1246.539463]Children1593gvfs・afc・volume1246,539408]Children:1568gvfs-gphoto2-vo[
1246.539413]Children1518trashapplet[
1246.539418]Children1526aultiload-apple[
1246.539423]Children:1532indicator-apple[
1246.539427]Children1528indicator,apple[
1246.539432]Children:1516wnck-applet[
1246.539437]Children1534notification-ar[
1246.539442]Children:1SW gvfsd-metadata[
1246.539447]Children1530clock-applet[
1246.539452Children:1558indicator-sessi[
1246.539457]Children:1556indicator-®e-se[
1246.539462Children:1574indicator-appli[
1246.539466]Children:1573indicatormessa[
1246.539471]Children1576indicator-sound[
1246.539476]Children:1615gvfsd-burn[
1246.539481Children1678gnome-terminal[
1246.539486]Children:1747ubuntuone-syncd[
1246.539499]Children:1772chrome[
1246.539495Children:178G chrome
1246.539500]Children:1962Bount.ntfs[
1246.539504]Children:1969bamfdaemon[
1294.162913The threadsearching finished最后用命令将已加载的内核卸载5rmmod thread_pid.ko总结
3.3模块是在内核空间运行的程序,实际上是一种目标对象文件,没有链接,不能独立Linux运行,但是可以装载到系统中作为内核的一部分运行,从而可以动态扩充内核的功能Linux提供了内核模块这种功能强大的扩展方式,它不仅弥补了单内核的一些不足,而且对性能没有影响通过内核模块机制,可以方便的进行内核开发和驱动开发,而事实上中大多数Linux驱动和文件系统都是已内核模块方式实现的在内核模块机制下,可以随时在需要的情况下加载新的内核模块,而不需要重新编译内核和引导系统当内核被加载到系统中时,他就成为内核源代码的一部分,与其他内核代码地位完全相同模块自身并不是独立的进程,它可以认为就是核心态运行同样,既然内核模块和内核其他部分地位一样,这就导致在开发式必须谨慎,因为可能一个小错误就会导致整个系统崩溃深刻理解内核模块编程,利用好内核模块的优势,无论是进行学习还Linux LinuxLinux是内核模块开发都是十分有益的【参考文献】邱铁,于玉龙,徐子川应用与开发典型实例精讲.北京清华大学出版社,
1..Linux
2010.5罗宇,陈燕晖,文艳军等曹所系统实验教程.北京电子工业出版社,
2..Linux
2009.2操作系统及网络资料
3.Linux。
个人认证
优秀文档
获得点赞 0