linux内核驱动入门程序 – TIC

自:http://blog.sina.com.cn/s/blog_5ae509900100bfft.html

装载驱动:

#include <linux/init.h>定义的宏__init __initdata//模块始初化的函数或数据标记,标记为初始化的项目会在初始化结束后丢弃;__exit __exitdata//模块清除阶段的函数或数据标记,标记为清除化项目会在内核示被配置为可卸载模块的情况下被丢弃。//内核将以上相应的目标对象放置在可执行文件的特殊ELF段中而让这些标记起做内核源码中的宏定义:#define __init__div(.init.text) __cold#define __initdata__div(.init.data)#define __exit__div(.exit.text) __exitused __cold#define __exitdata__div(.exit.data)//用来指定函数或数据所属区段,内核模块装载时从指定区段读取。如没有在指区段没有找到相应入口点,则装载失败。定义的宏module_init ( __init func );//模块装载入口

module_exit ( __exit func );//模块卸载出口如果未定义,则表明该驱动无法卸载

内核源码中的宏定义:#define module_init(initfn)\static inline initcall_t __inittest(void)\{ return initfn; }\int init_module(void) __attribute__((alias(#initfn)));#define module_exit(exitfn)\static inline exitcall_t __exittest(void)\{ return exitfn; }\void cleanup_module(void) __attribute__((alias(#exitfn)));

说明:__attribute__是gcc专有的,用来说明函数的属性weak 和 alias 分别是两个属性。weak 使得 main 这个符号在目标文件中作为 weak symbol 而不是 global symbol。用 nm 命令查看编译dummy.c 生成的目标文件可用看到 main 是一个 weaksymbol,它前面的标记是 W。而 alias 则使cleanup_module是#exitfn 的一个别名,#exitfn和cleanup_module必须在同一个编译单元中定义,否则会编译出错。

#include <linux/module.h>//设备驱动必须包含的头文件,包含可装载模块需要的大量符号和函数的定义常用宏:MODULE_LICENSE ( "Daul BSD/GPL" );//为模块指定代码所使用的许可证,有许多许可证类型。这里就不列举了。//如果模块没有显式地标记内核可识别的许可证,则会被假定为专有的。内核加载这种模块就会抱怨内核被“污染”。MODULE_AUTHOR ( AUTOHR );//模述模块作者MODULE_DESCRIPTION ( description );//对模块的描述信息MODULE_VERSION ( version );//指定模块版本MODULE_DEVICE_TABLE ( table_information );//模块设备表信息MODULE_ALIAS ( alternate_information );//指模块的相关文档信息EXPORT_SYMBOL ( symbol_name );EXPORT_SYMBOL_GPL ( symbol_name );//当需要模块层叠技术时(如:msdos文件系统依赖于由fat模块导出的符号),应该了解导出内核符号的用法。//EXPORT_SYMBOL_GPL使得要导出的模块只能被GPL许可证下的模块使用。符号必须在模块文件的全局部分导出,不能在函数中导出。//因为上面这两上宏将被扩展为一个特殊变量的声明,而该变量必须是全局的。该变量将在模块可执行文件的特殊部分(ELF段)保存。//装载时,内核通过这个段来寻找模块导出的变量。//更多宏定义请查看该头文件注释#include <linux/moduleparam.h>常用宏:module_param ( variable, type, perm );//用来创建模块参数的宏,用户可在装载模块时调整这些参数的值。//type类型://bool charp(字符指针) int invbool(反转逻辑) long short ushort uint ulong.module_param_array ( name, type, num, perm );//以上perm的值在 <linux/stat.h>中定义//如果perm被设置为0,就不会有对应的sysfs入口点,否则模块参数会在/sys/module中出现。//S_IRUGO,任一用户均可以读取:记忆方法:S=status(状态)IR=ReadOnly(只读) UGO=user,group,other(用户,用户组,其它)//S_IWUSE,只有root可以修改该参数#include <linux/kernel.h>常用函数:static inline int __cold printk(const char *s, …);//printk函数原型定义,用法跟标准C库printf类似。//定义此函数的原因是:内核模块装载后在内核空间执行,不能依赖C库函数。printk不到持浮点数(float类型)。#include <linux/errno.h>//在linux内核中,错误编译是定义在该头文件中的负整数。如下是部分定义:#define ERESTARTSYS512#define ERESTARTNOINTR513#define ERESTARTNOHAND514#define ENOIOCTLCMD515#define ERESTART_RESTARTBLOCK 516#define EBADHANDLE521#define ENOTSYNC522#define EBADCOOKIE523#define ENOTSUPP524#define ETOOSMALL525#define ESERVERFAULT526#define EBADTYPE527#define EJUKEBOX528#define EIOCBQUEUED529#define EIOCBRETRY530内核装裁与卸载演示代码,尽可能将上面的演示代码使用起来://在测试代码之前得重新编译内核,构建自己的代码树:

<div_one.c>#include <linux/init.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/moduleparam.h>#include <linux/stat.h>MODULE_LICENSE ( "Daul BSD/GPL" );static char* p_param = "hello word !";static int number = 1;static int div_begin ( void ){printk ( KERN_INFO "div_one begin,param:%s,number:%d", p_param, number );return 0;}static void div_end ( void ){printk ( KERN_ALERT "div_one end !" );}module_init ( div_begin );module_exit ( div_end );module_param ( p_param, charp, S_IRUGO );module_param ( number, int, S_IRUGO );EXPORT_SYMBOL_GPL ( div_begin );EXPORT_SYMBOL_GPL ( div_end );MODULE_AUTHOR ( "Leehom" );MODULE_DESCRIPTION ( "A simple demo !" );MODULE_VERSION ( "Version 1.0" );

<Makefile>ifneq ($(KERNELRELEASE),)obj-m:=div_one.oelseKERN_DIR:=/usr/src/linuxCURRENT_DIR:=$(shell pwd)default:$(MAKE) -C $(KERN_DIR) M=$(CURRENT_DIR)endif编译代码:[leehom@leehom div_one]$ makemake -C /usr/src/linux M=/home/leehom/Public/div_onemake[1]: Entering directory `/usr/src/linux-2.6.26’CC [M]/home/leehom/Public/div_one/div_one.oBuilding modules, stage 2.MODPOST 1 modulesCC/home/leehom/Public/div_one/div_one.mod.oLD [M]/home/leehom/Public/div_one/div_one.komake[1]: Leaving directory `/usr/src/linux-2.6.26’查看编译结果,内核模块文件div_one.ko已经构建好了。[leehom@leehom div_one]$ lsbuilt-in.oModule.markersdiv_one.cdiv_one.mod.cMakefilemodules.orderdiv_one.c~div_one.mod.oMakefile~Module.symversdiv_one.kodiv_one.o加载驱动模块:[leehom@leehom div_one]$ sudo insmod div_one.ko查看加载结果:[leehom@leehom div_one]$ dmesg | tail -n 1div_one begin,param:hello word !,number:1查看模块信息:[leehom@leehom div_one]$ modinfo div_one.kofilename:div_one.koversion:Version 1.0description:A simple demo !author:Leehomlicense:Daul BSD/GPLsrcversion:1E48889243E5036D4DD16AAdepends:vermagic:2.6.26 SMP mod_unload 686 4KSTACKSparm:p_param:charpparm:number:int卸载模块驱动并查看结果:[leehom@leehom div_one]$ sudo rmmod div_one.ko[leehom@leehom div_one]$ dmesg | tail -n 1div_one begin,param:hello word !,number:1<1>div_one end !加载模块驱动并传递参数:[leehom@leehom div_one]$ sudo insmod div_one.ko p_param=’test’ number=2[leehom@leehom div_one]$ dmesg | tail -n 1div_one begin,param:hello word !,number:1<1>div_one end !<6>div_one begin,param:test,number:2查看导出的符号:[leehom@leehom /]$ sudo cat -n /proc/kallsyms | grep div_one[sudo] password for leehom:3252500000000 a div_one.c[div_one]32526d097d000 t div_end[div_one]32527d097d010 t div_begin[div_one]

背着背包的路上,看过许多人,听过许多故事,

linux内核驱动入门程序 – TIC

相关文章:

你感兴趣的文章:

标签云: