飞凌嵌入式知识分享-Linux内核模块编译

本文主要讲解什么是Linux内核,以及通过多张图片展示Linux内核的作用、功能及基本编程方法,以便于读者能快速理解什么是Linux内核,能看懂Linux内核。
拥有超过1300万行的代码,Linux内核是世界上最大的开源项目之一,但是内核是什么,它用于什么?

一、什么是linux内核模块

内核是与计算机硬件接口的易替换软件的最低级别。它负责将所有以“用户模式”运行的应用程序连接到物理硬件,并允许称为服务器的进程使用进程间通信(IPC)彼此获取信息。

Linux内核与硬件的关系

内核可以通过所谓的中断来管理系统的硬件。 当硬件要与系统接口时,会发出一个中断,中断处理器,从而对内核执行相同的操作。 为了提供同步,内核可以禁用中断,无论是单个中断还是全部中断。 但是,在Linux中,中断处理程序不是在进程上下文中运行,而是在不与任何进程相关联的中断上下文中运行,这种特殊的中断上下文仅是为了让中断处理程序快速响应单个中断然后最终退出而存在 。

linux内核整体非常庞大,包含组件特别多,当我们把需要的部分包含到内核中,直接把需要的所有功能都编译到内核中会导致内核很大,而且当需要新增或者删除功能,又要重新编译,非常麻烦,因此linux提供了模块(Modele)的机制。

可以把内核比喻成一个很长的火车,每个车厢就是一个内核模块,内核在运行这个火车就会一直在开动,但是我们想在火车开动的情况下增加新的车厢,这个时候就需要insmod,意思就是往这个长长的火车车厢增加一个内核模块。

模块的特点:不编译入内核镜像;一旦加载和内核其他部分完全一样。

为了使读者对模块有个感性认知,先看一下简单的HelloWorld模块,代码如下:

二、Linux内核模块组成结构

一个Linux内核模块主要由以下几个部分组成。

1)模块加载函数(必须)

当通过 insmod 或 modprobe命令加载内核模块时,模块的加载函数会自动被内核执行,完成本模块的相关初始化工作。模块加载函数一般以__init标识声明

static int __init FuntionA(void)

{

}

module_init( FuntionA);

2)模块卸载函数(必须)

当通过 rmmod 命令卸载某模块时,模块的卸载函数会自动被内核执行,完成与模块加载函数相反的功能。 模块卸载函数一般以__exit标识声明:

static void __exit  FuntionB(void)

{

}

module_exit( FuntionB );

通常来说,模块卸载函数要完成与模块加载函数相反的功能,如下所示。

a)若模块加载函数注册了XXX,则模块卸载函数应该注销XXX。

b)若模块加载函数动态申请了内存,则模块卸载函数应释放该内存。

c)若模块加载函数申请了硬件资源(中断,DMA通道,I/O端口和I/O内存等)的占用,则模块卸载函数应释   放这些硬件资源。

d)若模块加载函数开启了硬件,则卸载函数中一般要关闭硬件。

3)模块许可证声明(必须)

模块许可证(LICENSE)声明描述内核模块的许可权限,如果不声明 LICENSE,模块被加载时,将收到内核被污染的警告。大多数情况下,内核模块应遵循GPL 兼容许可权。

Linux2.6 内核模块最常见的是以MODULE_LICENSE(“Dual BSD/GPL”)语句声明模块采用BSD/GPL 双LICENSE

4)模块参数(可选)是模块被加载的时候可以被传递给它的值,它本身对应模块内部的全局变量

用“module_param(参数名,参数类型,参数读/写权限)”为模块定义一个参数

例如: module_param(num,int,S_IRUGO);

5)模块导出符号(可选)可以导出符号(symbol,对应于函数或变量),这样其它模块可以使用本模块中的变量或函数

可以使用如下宏导出符号到内核符号表:

EXPORT_SYMBOL(符号名);

EXPORT_SYMBOL_GPL(符号名);

6)模块作者等信息声明(可选)

我们可以使用MODULE_AUTHOR,MODULE_DESCRIPTION,MODULE_VERSION,MODULE_DEVICE_TABLE,MODULE_ALLAS

分别声明模块的作者,描述,版本,设备表和别名

例如:

MODULE_AUTHOR(author);

MODULE_DESCRIPTION(description);

三、Linux内核模块的编译

首先为HelloWorld模块编写MakeFile文件

该MakeFile文件应该与源码位于同一目录

在Makefile中,在obj-m := helloworld.o这句中,.o的文件名要与编译的.c文件名一致。

如果一个模块包含多个.c文件(如file1.c、file2.c)则应该使用如下方式编写MakeFile:

Obj -m :=modulename.o

Modulename -obj :-file1.o file2.o

KERNELDIR ?= /usr/src/linux-headers-$(shell uname -r)指示当前linux系统内核的源码位置。

1.在Makefile及helloworld.c所在目录下,直接make,成功后查看当前目录下有无helloworld.ko文件产生,有则内核模块生成成功。

2.使用insmod命令,把此内核模块程序加载到内核中运行。结合lsmod及管道命令,查看内核模块程序在内核中是否正确运行。

四、总结

本文主要讲解了linux内核模块的概念和基本编程方法、内核模块组成结构,由于linux设备驱动以内核模块的形式存在,因此了解本文内容是编写任何设备驱动的必需。

(0)

相关推荐

  • 开发一个简单的内核程序

    ​前面文章我们介绍了如何编译一个内核,也了解到了编译内核并不难.今天这篇文章我们将介绍一下如何开发一个简单的内核程序. 实例源程序 用于态的程序类似,Linux的内核程序也是有规范的.用户态的程序必须 ...

  • 飞凌嵌入式技术分享-高效学习Linux内核——从源码中的宏下手

    在阅读Linux内核代码时,在代码的开头总是有各种各样的宏定义,了解熟悉这些宏定义,对于代码的理解和快速修改代码提供了便利.有些宏相对简单,一眼便可以了解作用,有些就稍微复杂一些,需要一些逻辑,今天就 ...

  • iMX8MQ如何在SPI总线上添加设备-飞凌嵌入式干货分享

    SPI接口设备是一款使用率较高的设备,在用户使用OKMX8MQ-C时可能需要添加新的SPI设备,或者将现有的SPI设备从当前的总线上更换到别的总线上,或更换片选. 对于SPI驱动不熟悉的人可能不是很了 ...

  • 飞凌嵌入式技术分享-NXP MFGTOOL 软件烧录原理

    在使用恩智浦公司i.MX6系列芯片时,会使用到MFGTool软件通过连接PC和开发板的USB A型口转Micro USB线来给相应的芯片烧录程序,本文主要讲解MFGTool软件烧写的原理. 一.软件的 ...

  • 飞凌嵌入式丨2020年技术干货合集大放送!

    亲爱的飞凌用户们 你们好哇 魔幻的2020即将过去 今年有些特殊,有些不容易 回看射雕处,千里暮云平 想必大家都有成长有收获 感谢你们一路以来的支持 2021即将到来 回顾2020 你是不是又博学了呢 ...

  • 飞凌嵌入式-千兆网之RGMII & SGMII解析

    一般来说,底板的千兆网大多选用RGMII和SGMII两种接口,也有可以拓展出更多网口的QSGMII接口. 这篇文章主要是对前两种常用的千兆网接口的介绍,以直观的方式对比这两种接口在引脚方面的不同,比较 ...

  • 飞凌嵌入式OKA40i开发板-模块初体验

    飞凌嵌入式OKA40i开发板-模块初体验

  • 嵌入式开发小记,实用小知识分享

    之前为了方便测试部门保存一些测试数据,需要临时开发一个简单的nanomsg server,与板子端的client在局域网内进行通信,接收client数据并保存.关于nanomsg的简单使用介绍可查看往 ...

  • 知识分享-全网最强硬盘知识飞凌一网打尽

    全网最强硬盘知识飞凌一网打尽 一.硬盘的基本分类 1.机械硬盘,最常见的就是2.5寸,3.5寸盘.以前还有1.8寸的微硬盘,但是已经见不到了,现在最多的就是2.5寸和3.5寸. 小知识点: 机械硬盘顾 ...

  • 飞凌干货|小巧嵌入式平台使用大型的数据库管理系统

    MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品.MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RD ...