linux内核模块设计
Linux操作系统的内核设计分析

Linux操作系统的内核设计分析Linux操作系统作为开源操作系统的代表,已经在各个领域得到了广泛应用。
而Linux操作系统的内核则是这个系统之所以能够运转的关键所在。
本文将就Linux操作系统的内核设计进行分析,并探讨其优劣之处。
一、Linux内核设计的基础Linux内核的设计基础主要包括以下几个方面:1. 开放源码Linux内核采用的是GPL协议,这意味着它是一个开放源码的项目。
这为世界各地的开发人员提供了极大的便利,方便他们进行开发和修改。
同时,这也确保了Linux内核的透明度,并且鼓励开发者贡献代码的同时,深度参与到Linux开源社区的构建和升级中。
2. 模块化Linux内核的构造采用的是模块化设计。
这种设计方式将内核代码分成独立的模块,每个模块都可以独立编译、加载和卸载。
采用模块化的设计,能够使得开发人员能够更加细致地打包、编译、并部署只包含他们需要的模块的系统。
3. 多任务Linux内核是一个基于多任务设计的系统。
这意味着它能够使得多个程序同时运行,并能够平滑高效地进行任务的切换。
这给开发人员提供了各种各样的自由,使得他们能够更加高效地进行开发。
4. 支持众多处理器架构Linux内核的支持范围非常广泛,它可以适配众多处理器架构。
这意味着一个制造商可以使用不同的处理器架构去生产设备,并且这些设备都能够安装和运行Linux操作系统。
5. 外层调用接口Linux内核支持开放式的外层调用接口。
这使得用户层可以很容易地调用Linux 内核执行某个任务。
这些用户层应用包括网上购物网站、应用程序和各种驱动程序。
6. 子系统Linux内核的子系统主要包括进程管理、内存管理、I/O管理和网络管理等。
二、Linux内核的优点Linux内核具有以下主要优点:1. 开源性Linux内核本身是一个开源的、由社区驱动的项目。
这意味着在它的附加组件和周边产品中,广大的开发者社区都可以为用户提供帮助和支持。
2. 安全性相比其他闭源操作系统,Linux内核在安全性方面更具优势。
5.7 内核模块设计

一个模块的简单例子(2.4内核)
//hello1.c #define MODULE 这是个模块程序 #include <linux/module.h> int init_module(void) { printk("<1>hello world!\n"); return 0; } void cleanup_module(void) { printk("<1>good bye!\n"); } ~/vmlinux/module/hello.c
模块使用
模块运行于内核空间,模块编程即为内核编 程. Linux内核中最重要的地方不能使用模块, 例如进程调度,内存管理等. 常用模块机制来实现文件系统管理,编写驱 动程序等.
模块实用程序modutils介绍
depmod:处理可加载内核模块的依赖关系. insmod:向正在运行的内核加载模块. lsmod:显示当前加载的内核模块信息. modprobe: 利用depmod创建的依赖文件 来自动加载相关的模块. rmmod: 从当前运行的内核中卸载内核模块
嵌入式系统程序设计
大连理工大学软件学院 嵌入式系统工程系 赖晓晨
内核模块设计
概述 模块实现机制 模块实例
一,概述
微内核体系结构 单一体系结构内核 模块
微内核体系结构的特点
内核只负责进程管理,内存管理,中断管理 文件系统,网络协议等其他部分运行于用户 空间 可扩展性好 不同层次之间消息传递开销比较大 典型应用:windows NT
一个模块的简单例子(编译加载续)
//hello.c #define MODULE #include <linux/module.h> int init_module(void) 修改消息级别 { MODULE_LICENSE("GPL"); printk("<0>hello world!\n"); return 0; } void cleanup_module(void) { printk("<0>good bye!\n"); } ~/vmlinux/module/hello3.c
Linux设备驱动程序原理及框架-内核模块入门篇

Linux设备驱动程序原理及框架-内核模块入门篇内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块内核模块介绍Linux采用的是整体式的内核结构,这种结构采用的是整体式的内核结构,采用的是整体式的内核结构的内核一般不能动态的增加新的功能。
为此,的内核一般不能动态的增加新的功能。
为此,Linux提供了一种全新的机制,叫(可安装) 提供了一种全新的机制,可安装) 提供了一种全新的机制模块” )。
利用这个机制“模块”(module)。
利用这个机制,可以)。
利用这个机制,根据需要,根据需要,在不必对内核重新编译链接的条件将可安装模块动态的插入运行中的内核,下,将可安装模块动态的插入运行中的内核,成为内核的一个有机组成部分;成为内核的一个有机组成部分;或者从内核移走已经安装的模块。
正是这种机制,走已经安装的模块。
正是这种机制,使得内核的内存映像保持最小,的内存映像保持最小,但却具有很大的灵活性和可扩充性。
和可扩充性。
内核模块内核模块介绍可安装模块是可以在系统运行时动态地安装和卸载的内核软件。
严格来说,卸载的内核软件。
严格来说,这种软件的作用并不限于设备驱动,并不限于设备驱动,例如有些文件系统就是以可安装模块的形式实现的。
但是,另一方面,可安装模块的形式实现的。
但是,另一方面,它主要用来实现设备驱动程序或者与设备驱动密切相关的部分(如文件系统等)。
密切相关的部分(如文件系统等)。
课程内容内核模块介绍应用层加载模块操作过程内核如何支持可安装模块内核提供的接口及作用模块实例内核模块应用层加载模块操作过程内核引导的过程中,会识别出所有已经安装的硬件设备,内核引导的过程中,会识别出所有已经安装的硬件设备,并且创建好该系统中的硬件设备的列表树:文件系统。
且创建好该系统中的硬件设备的列表树:/sys 文件系统。
(udev 服务就是通过读取该文件系统内容来创建必要的设备文件的。
)。
LINUX内核模块编译步骤

LINUX内核模块编译步骤编译Linux内核模块主要包括以下步骤:1.获取源代码2.配置内核进入源代码目录并运行make menuconfig命令来配置内核。
该命令会打开一个文本菜单,其中包含许多内核选项。
在这里,你可以配置内核以适应特定的硬件要求和预期的功能。
你可以选择启用或禁用各种功能、设备驱动程序和文件系统等。
配置完成后,保存并退出。
3. 编译内核(make)运行make命令开始编译内核。
这将根据你在上一步中进行的配置生成相应的Makefile,然后开始编译内核。
编译的过程可能需要一些时间,请耐心等待。
4.安装模块编译完成后,运行make modules_install命令将编译好的模块安装到系统中。
这些模块被安装在/lib/modules/<kernel-version>/目录下。
5.安装内核运行make install命令来安装编译好的内核。
该命令会将内核映像文件(通常位于/arch/<architecture>/boot/目录下)复制到/boot目录,并更新系统引导加载程序(如GRUB)的配置文件。
6.更新GRUB配置文件运行update-grub命令来更新GRUB引导加载程序的配置文件。
这将确保新安装的内核在下次启动时可用。
7.重启系统安装完成后,通过重启系统来加载新的内核和模块。
在系统启动时,GRUB将显示一个菜单,你可以选择要启动的内核版本。
8.加载和卸载内核模块现在,你可以使用insmod命令来加载内核模块。
例如,运行insmod hello.ko命令来加载名为hello.ko的模块。
加载的模块位于/lib/modules/<kernel-version>/目录下。
如果你想卸载一个已加载的内核模块,可以使用rmmod命令。
例如,运行rmmod hello命令来卸载已加载的hello模块。
9.编写和编译模块代码要编写一个内核模块,你需要创建一个C文件,包含必要的模块代码。
linux分层设计体系结构

linux分层设计体系结构Linux是一种开源的操作系统,其设计采用了分层的体系结构。
这种设计使得Linux具有高度的灵活性和可扩展性,同时也方便了系统的维护和管理。
本文将详细介绍Linux的分层设计体系结构。
在Linux的分层设计中,最底层是硬件层。
硬件层包括计算机的各种硬件设备,如处理器、内存、硬盘、网络接口等。
Linux通过设备驱动程序来管理和控制这些硬件设备,使其能够与操作系统进行交互。
在硬件层之上是内核层。
内核是操作系统的核心,负责管理系统的资源和提供各种系统服务。
Linux的内核是一个单独的模块,可以独立于其他软件进行开发和维护。
内核提供了各种系统调用接口,以及对进程、文件系统、网络和设备的管理和控制功能。
在内核层之上是库层。
库是一组共享的代码和函数,可以为应用程序提供常用的功能和服务。
Linux提供了许多不同的库,如C库、数学库、网络库等。
这些库可以被开发人员用来开发应用程序,提高开发效率和代码复用性。
在库层之上是应用层。
应用层包括各种应用程序和工具,如文本编辑器、图形界面、网络浏览器等。
这些应用程序可以通过系统调用接口与内核进行交互,并利用库提供的功能来实现各种任务和操作。
除了以上四个层次外,Linux还有其他一些重要的组件和模块。
例如,系统初始化和启动过程中,会加载引导程序和初始化程序;文件系统是用来组织和管理文件和目录的;网络协议栈是用来实现网络通信的;系统服务是用来提供各种系统功能和服务的。
这些组件和模块与其他层次之间相互关联,共同构成了Linux的完整体系结构。
Linux的分层设计体系结构具有许多优点。
首先,分层设计使得系统的各个组件和模块之间相互独立,可以分别进行开发、测试和维护,提高了开发和维护效率。
其次,分层设计使得系统的各个层次之间的接口清晰明确,方便了系统的扩展和升级。
此外,分层设计还提高了系统的稳定性和可靠性,一旦某个层次出现问题,不会对其他层次造成影响。
Linux的分层设计体系结构是一种高效、灵活和可扩展的设计方式。
Linux内核模块开发(简单)

Linux内核模块开发(简单)Linux系统为应⽤程序提供了功能强⼤且容易扩展的API,但在某些情况下,这还远远不够。
与硬件交互或进⾏需要访问系统中特权信息的操作时,就需要⼀个内核模块。
Linux内核模块是⼀段编译后的⼆进制代码,直接插⼊Linux内核中,在 Ring 0(x86–64处理器中执⾏最低和受保护程度最低的执⾏环)上运⾏。
这⾥的代码完全不受检查,但是运⾏速度很快,可以访问系统中的所有内容。
Intel x86架构使⽤了4个级别来标明不同的特权级。
Ring 0实际就是内核态,拥有最⾼权限。
⽽⼀般应⽤程序处于Ring 3状态--⽤户态。
在Linux中,还存在Ring 1和Ring 2两个级别,⼀般归属驱动程序的级别。
在Windows平台没有Ring 1和Ring 2两个级别,只⽤Ring 0内核态和Ring 3⽤户态。
在权限约束上,⾼特权等级状态可以阅读低特权等级状态的数据,例如进程上下⽂、代码、数据等等,但反之则不可。
Ring 0最⾼可以读取Ring 0-3所有的内容,Ring 1可以读Ring 1-3的,Ring 2以此类推,Ring 3只能读⾃⼰的数据。
1. 为什么要开发内核模块编写Linux内核模块并不是因为内核太庞⼤⽽不敢修改。
直接修改内核源码会导致很多问题,例如:通过更改内核,你将⾯临数据丢失和系统损坏的风险。
内核代码没有常规Linux应⽤程序所拥有的安全防护机制,如果内核发⽣故障,将锁死整个系统。
更糟糕的是,当你修改内核并导致错误后,可能不会⽴即表现出来。
如果模块发⽣错误,在其加载时就锁定系统是最好的选择,如果不锁定,当你向模块中添加更多代码时,你将会⾯临失控循环和内存泄漏的风险,如果不⼩⼼,它们会随着计算机继续运⾏⽽持续增长,最终,关键的存储器结构甚⾄缓冲区都可能被覆盖。
编写内核模块时,基本是可以丢弃传统的应⽤程序开发范例。
除了加载和卸载模块之外,你还需要编写响应系统事件的代码(⽽不是按顺序模式执⾏的代码)。
Linux 内核配置机制(make menuconfig、Kconfig、makefile)讲解

printk(KERN_WARNING fmt, ##arg) printk(KERN_DEBUG fmt, ##arg)
/* Module Init & Exit function */ static int __init myModule_init(void) {
/* Module init code */ PRINTK("myModule_init\n"); return 0;
图形
工具
前面我们介绍模块编程的时候介绍了驱动进入内核有两种方式:模块和直接编译进内核,并介绍 了模块的一种编译方式——在一个独立的文件夹通过makefile配合内核源码路径完成
那么如何将驱动直接编译进内核呢? 在我们实际内核的移植配置过程中经常听说的内核裁剪又是怎么麽回事呢? 我们在进行linux内核配置的时候经常会执行make menuconfig这个命令,然后屏幕上会出现以下 界面:
首页 业界 移动 云计算 研发 论坛 博客 下载 更多
process的专栏
您还未登录!| 登录 | 注册 | 帮助
个人资料
dianhuiren
访问:71424次 积分:1219分 排名:第8764名 原创:37篇 转载:127篇 译文:0篇 评论:3条
目录视图
摘要视图
订阅
《这些年,我们读过的技术经典图书》主题有奖征文 经理
这些配置工具都是使用脚本语言,如 Tcl/TK、Perl 编写的(也包含一些用 C 编写的代码)。本文
/dianhuiren/article/details/6917132
1/5
2012年04月 (6) 2012年03月 (15) 2012年02月 (16)
并不是对配置系统本身进行分析,而是介绍如何使用配置系统。所以,除非是配置系统的维护者,一般 的内核开发者无须了解它们的原理,只需要知道如何编写 Makefile 和配置文件就可以。
Linux内核模块

⼯作模式⼯作性质层次权限影响竞态运⾏⽅式应⽤程序USR 模式策略性⽤户层低局部局部主动内核模块SVC 模式功能性内核层⾼全局全局被挡Linux 内核模块1、什么是内核模块?内核模块是Linux 提供的⼀种机制,允许在内核运⾏时动态加载进内核中,具有两个特点: 1)内核模块本⾝不编译⼊内核映像,有效控制缩减内核镜像⼤⼩ 2)内核模块⼀旦被加载,他就和内核中的其他部分完全⼀样2、为什么需要内核模块?如果在内核编译时把所有的功能都编译进去,就会导致内核很⼤,⽽且要往内核中添加或删除功能时必须重新编译内核⽐如在Ubuntu 在通⽤PC 平台上,预先⽆法知道需要什么设备,就不知道预先编译什么驱动。
3、内核模块和应⽤程序的区别4、内核模块的基本构成|——两个函数(⼀般需要)| |——模块初始化(加载)函数:当内核模块加载进内核的时候,做⼀些准备⼯作| |——模块卸载函数:回收、清理资源||——授权(许可证声明)(必须):Linux 内核受GPL (General Public License )授权约束|——模块参数(可选):模块被加载时可以被传递给它的值,本⾝对应模块内的全局变量|——模块导出符号(可选)|——模块信息说明(可选)5、模块加载(初始化)函数⼀般以 __init 标识声明函数命名规则 xxx_init xxx 设备名 init 功能名(初始化)函数形式:static ini __init xxx_init(void ){/* 初始化代码* 返回值: 成功:0 失败:负数,绝对值是错误码* 应⽤层得到的返回值是-1,错误码保存到errno (每个进程有⼀个); 标准化errno.h 已经明确定义linux/errno.h */}注册⽅式: module_init(x); x 为模块初始化函数的⾸地址 6、模块卸载函数⼀般以 __exit 标识声明函数命名规则 xxx_exit xxx 设备名 exit 功能名(卸载)static ini __exit xxx_exit(void ){/* 释放代码 */}注册⽅式: module_exit(x); x为模块卸载函数的⾸地址7、模块许可证声明MODULE_LICENSE(_license) //_license就是授权名称的字符串//"GPL" [GNU Public License v2 or later]//"GPL v2" [GNU Public License v2]//"GPL and additional rights" [GNU Public License v2 rights and more]//"Dual BSD/GPL" [GNU Public License v2 or BSD license choice]//"Dual MIT/GPL" [GNU Public License v2 or MIT license choice]//"Dual MPL/GPL" [GNU Public License v2 or Mozilla license choice]8、模块声明与描述在Linux内核模块中,我们可以⽤MODULE_AUTHOR、MODULE_DESCRIPTION、MODULE_VERSION、MODULE_DEVICE_TABLE、MODULE_ALIAS分别来声明模块的作者、描述、版本、设备表和别名,例如:MODULE_AUTHOR(author);MODULE_DESCRIPTION(description);MODULE_VERSION(version_string);MODULE_DEVICE_TABLE(table_info);MODULE_ALIAS(alternate_name);对于USB、PCI等设备驱动,通常会创建⼀个MODULE_DEVICE_TABLE,表明该驱动模块⽀持的设备,如:/* 对应此驱动的设备列表 */static struct usb_device_id skel_table [ ] = {{USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) }, { } /* 表结束 */}};MODULE_DEVICE_TABLE (usb, skel_table);9、模块参数:在加载模块时,可以给模块传参头⽂件 linux/moduleparam.hA、传递普通变量module_param(name, type, perm);声明内核模块参数/*name - 接收参数的变量名type - 变量类型 Standard types are: byte, short, ushort, int, uint, long, ulong charp: a character pointer bool: a bool, values 0/1, y/n, Y/N. invbool: the above, only sense-reversed (N = true)perm - 权限 头⽂件 linux/stat.h #define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) #define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) #define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) #define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) #define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH)*/范例:int i = 0;module_param(i, int, 0644);运⾏:# insmod xxx.ko i=10B、传递数组参数module_param_array(name, type, nump, perm)/*声明内核模块数组参数name - 数组名type - 数组成员类型nump – ⼀个指向保存数组长度的整型变量的指针perm - 权限*/范例:int arr[] = {1,2,3,4,5,6};int len=0;module_param(arr, int, &len, 0644);运⾏:# insmod xxx.ko arr=1,2,3,4,5C、传递字符串参数module_param_string(name, string, len, perm)/*声明内核模块字符串参数name - 字符串缓存的外部名(传⼊变量名)string - 字符串缓存的内部名nump - 数组的数量perm - 权限*/范例:char insidestr[] = "hello world";module_param(extstr, insidestr, szieof(insidestr), 0644);运⾏:# insmod xxx.ko extstr="hello"10、编译内核模块如果⼀个内核模块要加载到某个内核中运⾏,则这个模块必须使⽤编译该内核镜像的源码进⾏编译,否则运⾏时会出错A、头⽂件(语法问题)B、编译结果(最主要影响)编译时符号表(只在编译时使⽤)运⾏时内核符号表# cat /proc/kallsyms 运⾏时内核符号表C、编译系统⽰例Makefile:# 内核模块的Makefile(模块源码在内核源码外,且内核先编译)# 1、找内核的Makefile# 2、内核的Makefile找内核模块的Makeifle内核模块的Makeifle定义要编译对象ifneq ($(KERNELRELEASE),)#要编译对象表⽰把demo.c编译成demo.ko obj-m = demo.oelse#内核源码⽬录KERNELDIR := /lib/modules/$(shell uname -r)/buildPWD := $(shell pwd)modules: $(MAKE) -C $(KERNELDIR) M=$(PWD) modulesendifclean: rm -rf .tmp_versions Module.symvers modules.order .tmp_versions .*.cmd *.o *.ko *.mod.cKERNELRELEASE 是在内核源码的顶层Makefile中定义的⼀个变量,在第⼀次读取执⾏此Makefile时,KERNELRELEASE没有被定义,所以make将读取执⾏else之后的内容。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验:Hello World模块 实验 模块
printk( )函数 函数
printk 函数在 Linux 内核中定义并且对模块可用,为内 核提供日志功能, 记录内核信息或用来给出警告。与 标准 C 库函数 printf 的行为相似。 每个printk() 声明都会带一个优先级。内核总共定义了 八个优先级的宏, 在linux/kernel.h中定义。若你不指明 优先级,DEFAULT_MESSAGE_LOGLEVEL这个默认 优先级将被采用。 信息添加到文件 /var/log/messages,可直接查看,或 者用命令dmesg查看。在X-windows下的终端insmod 一个模块,日志信息只会记录在日志文件中,而不在终 端打印。
内核模块概述
内核模块的卸载 当我们不需要内核模块了,为了减少系统资源的开销 为了减少系统资源的开销, 当我们不需要内核模块了 为了减少系统资源的开销 需要卸载时使用命令 #rmmod module_name 或者 #modprobe –r module_name 查看系统已经加载的模块,使用命令 查看系统已经加载的模块 使用命令 #lsmod
实验:Hello World模块 实验 模块
编译加载/卸载 编译加载 卸载: 卸载 在hello world模块目录上 模块目录上 #make 得到hello_world.ko就是产生的内核模块 在 就是产生的内核模块,在 得到 就是产生的内核模块 评估板上使用 #insmod hello_world.ko 和 #rmmod hello_world 观察控制台输出的结果
内核模块是一种没有经过链接,不能独立运行的目标文件, 是在内核空间中运行的程序。经过链接装载到内核里面成为 内核的一部分,可以访问内核的公用符号(函数和变量)。 内核模块可以让操作系统内核在需要时载入和执 行,在不 需要时由操作系统卸载。它们扩展了操作系统内核的功能却 不需要重新启动系统。 如果没有内核模块,我们不得不一次又一次重新编译生成单 内核操作系统的内核镜 像来加入新的功能。这还意味着一 个臃肿的内核。
实验:Hello World模块 实验 模块
模块参数 声明一个数组参数: module_param_array(name,type,num,perm); • name 数组的名子(也是参数名) • type 数组元素的类型 • num 是数组元素的个数,模块加载者拒绝比数组 能放下的多的值。2.6.9传递数组个数变量名, 2.6.11传递数组个数变量的地址。 • perm 是通常的权限值. 如果数组参数在加载时 设置。
Байду номын сангаас
内核模块概述
模块机制的优点: 模块机制的优点: 减小内核映像尺寸,增加系统灵活性; 节省开发时间;修改内核,不必重新编译整个内核。 模块的目标代码一旦被链入内核,作用和静态链接 的内核目标代码完全等价。 模块机制的缺点: 模块机制的缺点: 对系统性能有一定损失; 使用不当时会导致系统崩溃;
实验:Hello World模块 实验 模块
模块参数 宏MODULE_PARM_DESC() 用来注解该模块可以 接收的参数。该宏两个参数:变量名和一个对该变 量的描述。 模块可以用这样的命令行加载: ./insmod mymodule.ko myvariable=2 例子:hello-5.c
Linux 2.6内核模块设计 内核模块设计
内核模块概述
Linux内核是整体式结构,各个子系统联系紧密,作为一个大程 内核是整体式结构,各个子系统联系紧密, 内核是整体式结构 序在内核空间运行。 序在内核空间运行。
实验:Hello World模块 实验 模块
模块参数 module_param(name,type,perm); perm是一个权限值,控制谁可以存取模块参 数在 sysfs 中的表示。 perm 被设为 0, 就根本没有 sysfs 项 这个宏定义应当放在任何函数之外, 典型地 是出现在源文件的前面。 应该总是为变量赋初值。
内核模块概述
内核模块是如何被调入内核工作的? 内核模块是如何被调入内核工作的 当操作系统内核需要的扩展功能不存在时, 内核模块管理守护进程kmod执行modprobe 去加载内核模块。 modprobe遍历文件 /lib/modules/$(version)/modules.dep 来判 断是否有其它内核模块需要在该模块加载前 被加载。 最后modprobe调用insmod先加载被依赖的 模块,然后加载该被内核要求的模块。
内核模块概述
太多的设备驱动和内核功能集成 在内核中,内核过于庞大。 在内核中,内核过于庞大。如何 解决? 解决?
Linux内核引入内核模块 机制。通过动态加载内核 模块,使得在运行过程中 扩展内核的功能。不需要 的时候,卸载该内核模块。
内核模块概述
什么是内核模块? 什么是内核模块?
#include <linux/init.h> // for module_init() #include <linux/module.h> // must be include #include <linux/kernel.h> // for printk() static int __init hello_init(void) { printk(“Hello world\n”); “ ” return 0; } static void __exit hello_exit(void) { printk(“Hello module exit\n”); “ ” } module_init(hello_init); module_exit(hello_exit); MODULE_LICENSE(“GPL”); “ ” MODULE_AUTHOR(“hsq”); “ ”
实验:Hello World模块 实验 模块
模块参数 内核允许对模块指定参数,这些参数可在装载模块 时改变。在运行insmod或者modprobe命令时给出 参数的值。 insmod hellop.ko howmany=10 whom="Mom" 如何定义实现模块参数呢? 要传递参数给模块,首先将获取参数值的变量声明 为全局变量。然后使用宏moudle_param来声明 来声明 int myint = 3; module_param(myint, int,0);
实验:Hello World模块 实验 模块
说明: 说明
关于__init和__exit宏 关于 和 宏
如果该模块被编译进内核,而不是动态加载,则宏 __init的使用会在初始化完成后丢弃该函数并收回所占 内存。 如果该模块被编译进内核,宏__exit将忽略“清理收尾” 的函数。 这些宏在头文件linux/init.h定义,用来释放内核占用的 内存。例如启动时看到的信息“Freeing unused kernel memory: 236k freed”,正是内核释放这些函数所占用 空间时的打印信息。
实验:Hello World模块 实验 模块
说明: 说明 1) 模块入口函数为 模块入口函数为hello_init(), 由module_init() 宏指定,在模块被加载的时候被调用向系统 宏指定 在模块被加载的时候被调用向系统 注册, 就象应用程序的main()一样 主要来 一样,主要来 注册 就象应用程序的 一样 完成模块的初始化工作 2) 入口函数的返回值为 表示成功 非0表示失败 入口函数的返回值为0表示成功 表示成功, 表示失败 3) 模块的退出函数为 模块的退出函数为hello_exit(),由module_exit()宏 由 宏 指定,在模块被卸载是被调用向系统注销 在模块被卸载是被调用向系统注销,主要来完成 指定 在模块被卸载是被调用向系统注销 主要来完成 资源的清理工作,它被调用完毕后 它被调用完毕后,就模块就被内核清除了 资源的清理工作 它被调用完毕后 就模块就被内核清除了 4) 一个模块最少需要有入口和退出函数
注意: 注意: your_kernel_source,是你的linux kernel源代码的目录
实验:Hello World模块 实验 模块
Makefile说明 说明: 说明
为2.6版本内核构造模块 版本内核构造模块
首先需要有配置并构建好的2.6内核源代码树。而 且最好运行和模块对应的内核。 2.6 内核的模块要 和内核源代码树中的目标文件连接。 2.6 内核的构建系统Kbuild,使得内核源码外的内 核模块编译跟内核编译统一起来,无须手动给定这 些参数。 改变目录到用 -C 选项提供的内核源码目录,在那 里找到内核的顶层makefile。M= 选项使 makefile 在试图建立模块目标前, 回到模块源码目录。
实验:Hello World模块 实验 模块
参数数组的定义: 参数数组的定义: static int test[5] = {1,2,3,4,5}; static int num =5; module_param(num,int,0); module_param_array(test,int,num,0); MODULE_PARM_DESC(test, "test array"); 参数数组的加载方式: 参数数组的加载方式: insmod test.ko test=6,7,8,9,10 num=5
实验:Hello World模块 实验 模块
内核模块证书和内核模块文档说明
2.4内核后,引入识别代码是否在GPL许可下发布的机 制 。在使用非公开的源代码产品时会得到警告。通过 宏MODULE_LICENSE(“GPL”),设置模块遵守GPL证 书,取消警告信息。 宏MODULE_DESCRIPTION()用来描述模块的用途。 宏MODULE_AUTHOR()用来声明模块的作者。 宏MODULE_SUPPORTED_DEVICE() 声明模块支持 的设备。 这些宏都在头文件linux/module.h定义。使用这些宏只 是用来提供识别信息。 范例:hello-4.c