Hello world模块

本文介绍如何向内核中添加一个hello模块。该模块的功能是在模块加载时,向系统日志输出“hello world\n” 在模块卸载时输出“Good bye,cruel world!".

一个模块源代码一般有含有一个init函数(加载时调用)和一个exit函数(卸载时调用)。这两个函数由分别由宏module_init和module_exit调用。因而一个简单的Hello world模块源代码如下:

#include <linux/init.h><span style="white-space:pre">		</span>//这个头文件包含了你的模块初始化与清除的函数
#include <linux/module.h><span style="white-space:pre"> </span>//这个头文件包含了许多与模块加载有关的符号与函数的定义
<span style="white-space:pre"> </span>//如果模块需要参数传递,还可以参考moduleparam.h MODULE_LICENSE("GPL");<span style="white-space:pre"> </span>//表明本模块带有一个GPL的自由许可证,没有这行,加载模块时内核可能会抱怨
MODULE_AUTHOR("Windeal")<span style="white-space:pre"> </span>//author //模块加载时调用的函数
static int hello_init(void)
{
printk(KERN_ALERT "Hello world!\n");//printk是内核函数接口,会将内容输出到系统日志,KERN_ALERT表明输出优先级,printk也是行缓冲的
return 0;
} //模块卸载时调用的函数
static void hello_exit(void)
{
printk(KERN_ALERT "Good bye, cruel world!\n");
} module_init(hello_init);//宏,指定模块加载时调用的函数
module_exit(hello_exit);//宏,指定模块加载时调用的函数

关于MODULE_XXX宏做一个简单介绍:

MODULE_LICENSE<span style="white-space:pre">			</span>//许可证,具体许可证内容自行百度
MODULE_AUTHOR // 声明作者
MODULE_DESCRIPTION //对这个模块作一个简单的描述,这个描述是"human-readable"的
MODULE_VERSION // 这个模块的版本
MODULE_ALIAS // 这个模块的别名
MODULE_DEVICE_TABLE //告诉用户空间这个模块支持什么样的设备

编译、Makefile

前面我们已经写好了一个简单的hello模块,接下来要对模块进行编译。我们使用Makefile文件

# If KERNELRELEASE is defined, we've been invoked from the
# kernel build system and can use its language.
ifneq ($(KERNELRELEASE),)
obj-m := hello.o
# Otherwise we were called directly from the command
# line; invoke the kernel build system.
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build #KERNELDIR赋值,指代内核源代码目录 PWD := $(shell pwd) #当前目录
default:
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
endif

这是一个很有意思的Makefile脚本,当你在当前目录make的时候,它会执行两次。第一次执行的时候KERNELRELEASE未定义,因而会执行else分支的default目标的命令,即$(MAKE) -C $(KERNELDIR) M=$(PWD) modules .这条命令会进入内核源代码目录,执行内核源代码根目录下的Makefile,根目录下的Makefile会定义KERNELRELEASE,并切换到当前目录,再执行一遍当前目录的Makefile。此时KERNELRELEASE已被定义,因而会执行obj-m
:= hello.o 这条命令。从而整个依赖关系才完整,生成目标文件hello.ko。

ifeq ($(KERNELRELEASE),)目前,并无用处,它的由来是指在Linux源码根目录下的Makefile编译内核时,KERNELRELEASE宏会被定义,那么如果是从源码根目录开始的make则会将myhello.o模块编译进内核。

$(MAKE) -C $(KERNELDIR) M=$(PWD) modules 是Makefile的规则:这里的$(MAKE)就相当于make,-C 选项的作用是指将当前工作目录转移到你所指定的位置。“M=”选项的作用是,当用户需要以某个内核为基础编译一个外部模块的话,需要在make modules 命令中加入“M=dir”,程序会自动到你所指定的dir目录中查找模块源码,将其编译,生成ko文件。

模块加载:

编译好的模块hello.ko需要加载如内核才能使用。

sudo insmod XXX<span style="white-space:pre">		</span>#加载模块
sudo lsmod<span style="white-space:pre"> </span>#查看已加载的所有模块
sudo rmmod XXX<span style="white-space:pre"> </span>#卸载模块

而我们的prink输出会写入系统日志,可以通过dmesg查看。

因此我们的测试过程如下:

windeal@ubuntu:driver$ lsmod | grep hello   #确认当前没有加载hello模块
windeal@ubuntu:driver$ sudo insmod hello.ko #加载hello.ko模块
windeal@ubuntu:driver$ dmesg<span style="white-space:pre"> </span>#查看系统日志
[190444.174802] Hello world!
windeal@ubuntu:driver$ lsmod | grep hello<span style="white-space:pre"> </span>#查看是否加载了hello模块
hello 12449 0
windeal@ubuntu:driver$ sudo rmmod hello<span style="white-space:pre"> </span>#卸载hello模块
windeal@ubuntu:driver$ dmesg<span style="white-space:pre"> </span>#查看系统日志
[190444.174802] Hello world!
[190487.913667] Good bye, cruel world!
windeal@ubuntu:driver$ lsmod | grep hello<span style="white-space:pre"> </span>#查看模块是否被卸载了
windeal@ubuntu:driver$

图:

 
 

 

Linux驱动入门——构建和运行模块的更多相关文章

  1. Linux驱动学习之常用的模块操作命令

    1.常用的模块操作命令 (1)lsmod(list module,将模块列表显示),功能是打印出当前内核中已经安装的模块列表 (2)insmod(install module,安装模块),功能是向当前 ...

  2. Linux驱动之内核加载模块过程分析

    Linux内核支持动态的加载模块运行:比如insmod first_drv.ko,这样就可以将模块加载到内核所在空间供应用程序调用.现在简单描述下insmod first_drv.ko的过程 1.in ...

  3. linux 驱动入门1

    世事艰难,人生不易. 夜深人静时候,回顾过去,往事历历在目.创南京,混苏州,下上海.都付出了巨大的努力.多少个不眠的夜晚,在冥思苦想.天生愚钝.又不是学计算机的.一直没较为深刻的理解 编程什么东西,一 ...

  4. linux 驱动入门3

    不吃苦中苦,难为人上人.努力,给老婆孩子提供个良好的生活居住环境. http://www.cnblogs.com/nan-jing/articles/5806399.html 上文提到.可以自动创建了 ...

  5. linux 驱动入门4

    不吃苦中苦,难为人上人.努力,给老婆孩子提供个良好的生活居住环境.http://www.cnblogs.com/nan-jing/articles/5806399.html上文提到了如何创建proc节 ...

  6. linux 驱动入门5

    慢慢的开始转驱动,目前比较有时间,一定要把驱动学会.哎.人生慢慢路,一回头.已经工作了八九年了.努力.在买套房.改退休了.学驱动.个人认为首先要熟悉驱动框架.慢慢来.心急吃不了热豆腐. 看网上都说的设 ...

  7. linux 驱动入门2

    不吃苦中苦,难为人上人.努力,给老婆孩子提供个良好的生活居住环境. http://www.cnblogs.com/nan-jing/articles/5775038.html 这里提到.有这么多牛人. ...

  8. Linux驱动之建立一个hello模块

    目标:在开发板上执行insmod hello.ko能在控制台打印出hello init:接着执行rmmod会在控制台打印出hello exit 建立一个hello模块的步骤如下: 1.建立一个hell ...

  9. linux 驱动入门6

    看/sys目录经常看到bus device driver class. 这也是网上大量说的驱动驱动模型.这些的关系得熟悉得明白吧.是的.今天我先不整他们的关系.先逐个击破,然后再统一来理清楚他们之间的 ...

随机推荐

  1. CSS Margin(外边距)

    CSS Margin(外边距) 一.简介 CSS margin(外边距)属性定义元素周围的空间. margin 清除周围的(外边框)元素区域.margin 没有背景颜色,是完全透明的. margin ...

  2. Java:出现错误提示(java.sql.SQLException:Value '0000-00-00' can not be represented as java.sql.Date)

    Java:出现错误提示(java.sql.SQLException:Value '0000-00-00' can not be represented as java.sql.Date) 原因分析: ...

  3. 20145216 史婧瑶《Java程序设计》第6周学习总结

    20145216 <Java程序设计>第6周学习总结 教材学习内容总结 第十章 输入/输出 10.1 InputStream与OutputStream 如果要将数据从来源中取出,可以使用输 ...

  4. zabbix分布式监控系统安装配置

    zabbix简介: zabbix(音同 zæbix)是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案. zabbix能监视各种网络参数,保证服务器系统的安全运营:并提供灵 ...

  5. iOS开发中的地图开发

    显示地图: 1.导入头文件 #import <MapKit/MapKit.h> 如果同时需要用户定位的话还需要 #import <CoreLocation/CoreLocation. ...

  6. POJ_1159 Palindrome (线性动态规划+滚动数组)

    题意是说,给定一个字符串,问至少还需要插入多少个字符才能使得该字符串成为回文字符串. 这道题一开始做的时候用了一个简单的动态规划,开了一个5000*5000的数组,用递归形式实现,代码如下: 其中d[ ...

  7. Oracle18c创建不带C##的用户

    18c数据库分两种数据库CDB(容器数据库).PDB(可插拔数据库) 数据库安装完成之后,默认是CDB 创建一个用户,必须要用C##开头,但使用PDB没有这个限制 1. 先查看PDB数据库servic ...

  8. P4开源Tutorials教程样例实战及对P4v1.1规范的初分析

    Github链接:Github-P4Lang-Tutorials-p4v1.1 前言 本文主要对Barefoot开源教程中的p4v1.1实例simple_router的实战步骤进行记录与阐述,希望能帮 ...

  9. Ubuntu 安装 networkx

    参考:ubuntu 下NetworkX的安装和使用 Dependences pip setuptools Commands 1.install networkx sudo pip install ne ...

  10. close与shutdown系统调用

    使用多线程时,pthread_create的参数flag有CLONE_FILES, 最终调用do_fork(),并且会根据CLONE_FILES标志来调用copy_files()来共享父进程中的文件描 ...