• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C语言 > 解析Linux内核的基本的模块管理与时间管理操作

解析Linux内核的基本的模块管理与时间管理操作

作者:喝醉的毛毛虫 字体:[增加 减小] 来源:互联网 时间:2017-05-28

喝醉的毛毛虫 通过本文主要向大家介绍了linux内核模块,linux内核模块编程,linux内核模块编译,linux 内核模块加载,linux内核模块编写等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

内核模块管理
Linux设备驱动会以内核模块的形式出现,因此学会编写Linux内核模块编程是学习linux设备驱动的先决条件。

Linux内核的整体结构非常庞大,其包含的组件非常多。我们把需要的功能都编译到linux内核,以模块方式扩展内核功能。

先来看下最简单的内核模块

#include <linux/init.h> 
#include <linux/module.h> 
 
 
static int __init hello_init(void) 
{ 
    printk(KERN_ALERT "Hello world! %s, %d\n", __FILE__, __LINE__); 
    return 0; 
} 
 
static void __exit hello_exit(void) 
{ 
 
    printk(KERN_ALERT "Hello world! %s, %d\n", __FILE__, __LINE__); 
} 
 
module_init(hello_init); 
module_exit(hello_exit); 
 
MODULE_LICENSE("GPL"); 
MODULE_AUTHOR("Mikcy Liu"); 
MODULE_DESCRIPTION("A simple Module"); 
MODULE_ALIAS("a simple module"); 
</div>

头文件init.h包含了宏_init和_exit,它们允许释放内核占用的内存。
module_init()和hello_exit()是模块编程中最基本也是必须的两个函数。
module_init()是驱动程序初始化的入口点。
hello_exit是模块的退出和清理函数。此处可以做所有终止该驱动程序时相关的清理工作。

内核模块中用于输出的函数式内核空间的printk()而非用户空间的printf(),printk()的用法和printf()相似,但前者可定义输出级别。printk()可作为一种最基本的内核调试手段

前者可以定义输出级别,在 <内核目录>/include/linux/kernel.h中

#define KERN_EMERG   "<0>"  /* system is unusable          */ 
#define KERN_ALERT   "<1>"  /* action must be taken immediately   */ 
#define KERN_CRIT    "<2>"  /* critical conditions         */ 
#define KERN_ERR    "<3>"  /* error conditions           */ 
#define KERN_WARNING  "<4>"  /* warning conditions          */ 
#define KERN_NOTICE   "<5>"  /* normal but significant condition   */ 
#define KERN_INFO    "<6>"  /* informational            */ 
#define KERN_DEBUG   "<7>"  /* debug-level messages         */ 
</div>

未设定级别的,在<内核目录>/kernel/printk.c中定义

/* printk's without a loglevel use this.. */ 
#define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */ 
 #define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything MORE serious than KERN_DEBUG */ 
</div>

只有当printk打印信息时的loglevel小于DEFAULT_CONSOLE_LOGLEVEL的值(优先级高于console loglevel),这些信息才会被打印到console上。

模块声明与描述

  •    在linux模块中,我们可以使用
  •    MODULE_LICENSE(license)   //定义模块的license,一般为GPL,或相关公司的license
  •    MODULE_AUTHOR             //模块的作者
  •    MODULE_DESCRIPTION        //对模块程序的描述,string
  •    MODULE_VERSION            //版本
  •    MODULE_DEVICE_TABLE       //模块程序所支持的设备,string
  •    MODULE_ALIAS              //别名
  •    MODULE_PARM(var,type)     //模块参数

模块编译
首先看看Makefile文件:

obj-m := hello.o 
KERNEL_BUILD := /lib/modules/$(shell uname -r)/build 
all: 
    make -C $(KERNEL_BUILD) M=$(shell pwd) modules 
clean: 
    -rm -rf *.o *.ko *.mod.c .*.cmd *.order *.symvers .tmpversions 
KERNELBUILD :=/lib/modules/$(shell uname -r)/

</div>

build是编译内核模块需要的Makefile的路径,Ubuntu下是/lib/modules/2.6.31-14-generic/build

如果是Arm平台的开发板,则-C选项指定的位置(即内核源代码目录),其中保存有内核的顶层Makefile文件.

make -C $(KERNEL_BUILD) M=$(shell pwd) modules 编译内核模块。-C 将工作目录转到KERNEL_BUILD,调用该目录下的Makefile,并向这个Makefile传递参数M的值是$(shell pwd) modules。

M=选项让该makefile在构造modules目标之前返回到模块源代码目录。然后modules目标指向obj-m变量中设定的模块

执行make命令开始编译模块,生成hello.ko,执行make clean可清除编译产生的文件。

1、添加模块

   insmod hello.ko

</div>

2、查看模块

  lsmod | grep hello

</div>

   lsmod命令实际上读取并分析/proc/modules文件,也可以cat /proc/modules文件

   在模块所在目录下执行

    modinfo  hello.ko可以查看模块信息,如下所示

filename:    hello.ko
alias:     a simple module
description:  A simple Module
author:     Mikcy Liu
license:    GPL
srcversion:   875C95631F4F336BBD4216C
depends:    
vermagic:    3.5.0-17-generic SMP mod_unload modversions 686

</div>

3、删除模块

 rmmod hello
</div>


模块加载函数

Linux内核模块加载函数一般以__init标识声明,典型的模块加载函数的形式如下:

static int __init initialization_function(void) { 
   //初始化代码  
}  
module_init(initialization_function); 
</div>

    模块加载函数必须以“module_init(函数名)”的形式指定。它返回整形值,若初始化成功,应返回0。而在初始化失败时。应该返回错误编码。

    在linux内核里,错误编码是一个负值,在<linux/errno.h>中定义,包含-ENODEV、-ENOMEM之类的符号值。返回相应的错误编码是种非常好的习惯,因为只有这样,用户程序才可以利用perror等方法把它们转换成有意义的错误信息字符串。

    在linux2.6内核中,所有标识为__init的函数在连接的时候都会放在.init.text(这是module_init宏在目标代码中增加的一个特殊区段,用于说明内核初始化函数的所在位置)这个区段中,此外,所有的__init函数在区段.initcall.init中还保存着一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数,并在初始化完成后释放init区段(包括.init.text和.initcall.init等)。所以大家应注意不要在结束初始化后仍要使用的函数上使用这个标记。

模块卸载函数

Linux内核卸载模块函数一般以__exit标识声明,典型的模块卸载函数的形式如下:

static void __exit cleanup_function(void) {   
 //释放代码  
}  
module_exit(cleanup_function); 
</div>

模块卸载函数在模块卸载时被调用,不返回任何值,必须以”module_exit(函数名)”的

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • 解析Linux内核的基本的模块管理与时间管理操作

相关文章

  • 2017-05-28typedef和#define的用法以及区别
  • 2017-05-28详解C++文件读写操作
  • 2017-05-28C语言求向量和的两则问题解答分享
  • 2017-05-28C语言之整数划分问题(递归法)实例代码
  • 2017-05-28C/C++ ip地址与int类型的转换实例详解
  • 2017-05-28Recommended C Style and Coding Standards中文翻译版第1/3页
  • 2017-05-28C++实现动态分配const对象实例
  • 2017-05-28C语言中对于循环结构优化的一些入门级方法简介
  • 2017-05-28使用VC6.0对C语言程序进行调试的基本手段分享
  • 2017-05-28简单总结C++中的修饰符类型

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C++中的delete不会将操作数置0
    • C 语言restrict 关键字的使用浅谈
    • 简单实现C++复数计算器
    • 深入解析C++和JAVA的字符串
    • 浅析VC++中的头文件包含问题
    • C++ 先对数组排序,在进行折半查找
    • c++判断是否为目录的示例分享
    • 浅析内存对齐与ANSI C中struct型数据的内存布局
    • C++中4种强制类型转换的区别总结
    • 支持C++,python,java等语言的跨平台的农历库(天文历算法)

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有