做内核驱动第一步都是学习如何添加模块,这是基础,有了这个基础,剩下就是写代码了。

  由于2.4到2.6内核版本的更新,无论是系统调用还是模块添加机制都有了巨大的变化,本人也因此饱经挫折,最后在3.0.101版本的内核下成功。作为开源运动的支持者,自认为有必要把自己的经历分享出来,以供后来学习者分享与交流。

再次声明,本博客只分享我遇到了的问题,没有交流的不代表不难或者不会遇到问题,只是我没遇到,如果有阅读本博客的朋友遇到了问题,非常欢迎大家一起讨论,技术就是这么成长的!

  关于添加模块,步骤上还是那三步。

  1.编写模块函数

  编写内核模块时必须要有的两个函数 :

  1> 加载 函数:

  static int func1_init(void)

  2> 卸载函数 无返回值

  static void func2_exit(void)

  这里值得注意的是三点,一是卸载函数必须是void,即无返回型,否则会报错。其二是推荐把加载函数改写成static int __init func1_init(void),卸载函数同理。这里使用__init是利用2.6内核以后的宏机制,具体机制。。。还在学习中。第三点就是人尽皆知的,加载函数的名字必须写成*_init的样子,卸载函数必须是*_exit的样子。

 

  2.其次就是Makefile了。

  这方面的文章比较多,网上也讲得非常详细,我就大概讲一下模板和每步的意义。

  

obj-m := hello.o

kernel_path=/usr/src/linux-headers-$(shell uname -r)

all:

make -C $(kernel_path) M=$(PWD) modules

clean:

make -C $(kernel_path) M=$(PWD) clean

obj -m:= hello.o // 产生 hello 模块的目标

kernel_path // 定义内核源文件目录

all :

make -C $(kernel_path) M=$(PWD) modules

// 生成内核模块参数为内核源代码目录以及模块所在目录

clean:

make -C $(kernel_path) M=$(PWD) clean

// 清除生成的模块文件以及中间文件

这里就要尤为注意了,在2.6版本以后,引入了如下机制。2.6中模块的编译需要配置过的内核源码;编译、连接后生成的内核模块后缀为.ko;编译过程首先会到内核源码目录下,读取顶层的Makefile文件,然后再返回模块源码所在目录。

接下来要讲得就是最折磨人的改变了。

2.4内核下, 执行`cat /proc/ksyms`可看到内核符号在名字后还跟随着一串校验字符串,此校验字符串与内核版本有关。在内核源码头文件linux/modules 目录下存在许多*.ver文件,这些文件起着为内核符号添加校验后缀的作用,如ksyms.ver 文件里有一行 #define printk _set_ver(printk)。linux/modversions.h 文件会包含全部的 ver文件 。所以当模块包含linux/modversions.h文件后,编译时,模块里使用的内核符号实质是带有校验后缀的内核符号。在加载模块时,如果模块中所使用内核符号的校验字符串与当前运行内核所导出的相应的内核符号的校验字符串不一致,即当前内核空间并不存在模块所使用的内核符号,就会出现"Invalid module format "的错误。

为内核符号添加校验字符串来验证模块的版本与内核的版本是否匹配是繁杂和浪费内核空间的;而且随着SMP(对称多处理器)、PREEMPT(可抢占内核)等机制在2.6内核的引入和完善,模块运行时对内核的依赖不仅取决于内核版本,还取决于内核的配置,此时内核符号的校验码是否一致不能成为判断模块可否被加载的充分条件。2.6 内核下,在linux/vermagic.h中定义有VERMAGIC_STRING,VERMAGIC_STRING不仅包含内核版本号,还包含有内核使用的gcc版本,SMP与PREEMPT等配置信息。模块在编译时,我们可以看到屏幕上会显示"MODPOST"。在此阶段, VERMAGIC_STRING会添加到模块的modinfo段。 在内核源码目录下scripts/mod/modpost.c文件中可以看到模块后续处理部分的代码。模块编译生成后,通过`modinfo mymodule.ko`命令可以查看此模块的vermagic等信息。2.6 内核下的模块装载器里保存有内核的版本信息,在装载模块时,装载器会比较所保存的内核vermagic与此模块的modinfo段里保存的vermagic信息是否一致,两者一致时,模块才能被装载。譬如Fedora core 4 与core 2 使用的都是2.6 版本内核, 在Fedore Core 2下去加载Fedora Core4下编译生成的hello.ko,会出现"invalid module format" 错误。

因此,细心的朋友注意到我给出的Makefile模板中编译目标是内核源码树。这里必须是这样,否则会出错。而且必须对应,即,如果你当前内核版本是3.0.101,就必须是以3.0.101的内核源码树为目标进行编译得到*.ko,否则会报错。反之亦然。两者必须一一对应,这一点希望朋友们务必注意,否则会痛不欲生。

以上就是我学习这部分最痛苦最值得分享的部分了,希望可以帮到大家。

由于2.6下各位朋友肯定希望自己的模块能兼容2.4下的模式,所以,我这里再提供一套Makefile,有IBM官方给出,值得学习。

# Makefile2.6
ifneq ($(KERNELRELEASE),)
#kbuild syntax. dependency relationshsip of files and target modules are listed here.
mymodule-objs := file1.o file2.o
obj-m := mymodule.o
else
PWD := $(shell pwd)
KVER ?= $(shell uname -r)
KDIR := /lib/modules/$(KVER)/build
all:
$(MAKE) -C $(KDIR) M=$(PWD)
clean:
rm -rf .*.cmd *.o *.mod.c *.ko .tmp_versions
endif

linux内核自己添加模块(内核版本:3.0.101)的更多相关文章

  1. 解析 Linux 内核可装载模块的版本检查机制

    转自:http://www.ibm.com/developerworks/cn/linux/l-cn-kernelmodules/ 为保持 Linux 内核的稳定与可持续发展,内核在发展过程中引进了可 ...

  2. linux内核添加模块

    参考: http://blog.csdn.net/gaoguoxin2/article/details/50220665 动态添加模块不需要编译内核. LINUX的模块主要由6部分组成: 1.模块的加 ...

  3. 向linux内核中添加外部中断驱动模块

    本文主要介绍外部中断驱动模块的编写,包括:1.linux模块的框架及混杂设备的注册.卸载.操作函数集.2.中断的申请及释放.3.等待队列的使用.4.工作队列的使用.5.定时器的使用.6.向linux内 ...

  4. linux 实现centos7在线升级最新版本内核

    Kernel  (内核)是操作系统的核心,掌握所有硬件设备的控制权,也就是说,你所希望计算机帮你完成的各项工作,都需要通过内核的帮助才能完成,当然,如果我们想完成的某个功能是内核没有的,则内核不会操控 ...

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

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

  6. Linux内核开发之将驱动程序添加到内核

    驱动程序添加到内核 一.概述: 在Linux内核中增加程序需要完成以下三项工作: 1.将编写的源代码复制到Linux内核源代码的相应目录 2.在目录的Kconfig文件中增加新源代码对应项目的编译配置 ...

  7. Linux内核的五大模块

    Linux内核的五大模块 (转自)https://blog.csdn.net/huangjingbin/article/details/19396235 Linux内核的五大模块 1.进程调度模块 2 ...

  8. 在Linux内核中添加系统调用,并编译内核

    1 环境准备 运行系统:vmware下安装的ubuntu10.10 32bit桌面版. 编译内核版本: linux-2.6.32.63 内核目录: /home/wanchouchou/linuxKer ...

  9. Linux内核@系统组成与内核配置编译

    Linux系统由什么组成? 由用户空间(应用程序+GNU C标准库)和内核空间(系统调用接口+内核+内核架构代码)组成. Linux内核到底是什么?以及组成. ARM的七种操作级别? 内核网络协议栈( ...

随机推荐

  1. dategrid快速录入一行数据的一波操作

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  2. mysql-profiling详解

    要想优化一条 Query,我们就需要清楚的知道这条 Query 的性能瓶颈到底在哪里,是消耗的 CPU计算太多,还是需要的的 IO 操作太多?要想能够清楚的了解这些信息,在 MySQL 5.0 和 M ...

  3. [Java反射基础二]获取类的信息

    本文接上文“Class类的使用”,以编写一个用来获取类的信息(成员函数.成员变量.构造函数)的工具类来讲解"反射之获取类的信息" 1.获取成员函数信息 /** * 获取成员函数信息 ...

  4. JavaScript JSON AJAX 同源策略 跨域请求

    网页和Ajax和跨域的关系 1 Ajax使网页可以动态地.异步地的与服务器进行数据交互,可以让网页局部地与服务器进行数据交互 2 Ajax强调的是异步,但是会碰到跨域的问题. 3 而有很多技术可以解决 ...

  5. Android错题集

    在Android学习的过程中,遇到过很多迷之问题,在这里记下以防以后忘记,也可以顺便帮助一下遇到了相同问题的朋友. 1.自定义控件文字大小错误: 在自定义控件中获取的getDimension值为px值 ...

  6. 查看源代码HTML

    HTML 提示 - 如何查看源代码 如果您想找到其中的奥秘,只需要单击右键,然后选择“查看源文件”(IE)或“查看页面源代码”(Firefox),其他浏览器的做法也是类似的.这么做会打开一个包含页面 ...

  7. Java 调用 Rest api 设置经典 Linux 虚拟机的实例启停

    现象描述 用户可以通过 Rest API 设置经典 Linux 虚拟机实例的启停.在调用该 API 时需要通过 Azure Active Directory(下文简称 AAD) 获取 Token,但是 ...

  8. MYSQL连接相关参数和状态值详解

    针对mysql的连接参数和状态值,本文做些介绍和对比 一.MYSQL连接参数变量 1.常用连接数限制参数 show variables like '%connect%'; | max_connect_ ...

  9. 动态给table添加动态航

    <html> <head> <title>usually function</title> <meta http-equiv="Cont ...

  10. x64 QWORD Xor shellcode encoder

    #!/usr/bin/env python #Filename: Xor_QWORD_x64.py #coding=utf-8 import re import sys import random i ...