内核模块2 | 学习笔记

简介: 快速学习模块编写2

开发者学堂课程【物联网开发-Linux 驱动开发实操演练:内核模块2】学习笔记,与课程紧密联系,让用户快速学习知识。

课程地址https://developer.aliyun.com/learning/course/657/detail/10870


内核模块2


内容介绍:

一、模块编写三要素

二、入口函数的使用介绍

三、出口函数的使用介绍

四、编写内核模块的准备工作

五、编写内核模块


一、模块编写三要素

1. 入口(加载)

Module_init(入口函数名);

2. 出口(卸载)

Module_exit(卸载函数名);

3. GPL协议申明

MODULE_LICENSE(GPL)


二、入口函数的使用介绍

1.观察入口函数

在 source insight 中搜索 module_init和 module_exit,观察内核里面其他的驱动如何使用内核模块从 module_init 和 module_exit,搜索如图所示:

图片1.png

观察发现,内核里面有很多驱动在使用模块三要素。

会发现在使用 module_init 时,会发现使用了一个其他函数:nmikbd_init,如图:

对于这个函数,需要观察它的返回值是否为 init,形参是否为 void。

总结发现:入口函数的返回值是init 类型+函数名,它的形参为 void。

图片2.png

因此需要分装一个函数名,传递给module_init的宏,注册到内核里

platform_set drvdata(pdev.NULL)

free_irq(IRQ_AMIGA_CIAASP,dev

input_unregister_device(dev);

return 0;

static structplatform_driver amikbd_driver =《

remove exit_p(amikbd_remove)

driver

.name amiga-keyboard",

Owner THIS_MODULE,

),

);static int __init amikbd_init(void)

return platform_driver_probe(&amikbd_driver, amikbd_probe);

module_init(amikbd_init);

static void __exit amikbd_exit(void)

platform_driver_unregister(&amikbd_driver);

module_exit(amikbd_exit);

MODULE ALIAS(、nlatform:amiea-kevhoard!)

2. 编写内核模块的入口函数

在编写的时候,加上--init,作用是将地址统一放在--init 的段里面,统一进行加载。

Module_init(入口函数名);

Int  __init xx_func(void)

(

)


三、出口函数的使用介绍

1.观察出口函数

在内核里面搜素 module_exit,内核中 exit 较多,简单搜索即可

image.png

找到一个入口,进入随机找一个出口函数

If  acpt ac dir)

return -ENODEV:

end1f

result= acpi_bus_register_driver(&acpi_ac_driver); (result e)(

5 CONFIG ACPI PROCFS POWER

If  acpi_unlock_ac_dir(acpi_ac_dir);

return -ENODEV;

return

static void exitacpi_ac_exit(void)

67  acpi bus unregister.driver(&acpi driver

8:

9 ifdef CONFIG ACPI PROCFS POWER

B: acpi unlock ac dir(acpt acdir);

123 #endif

return;

5:

6:module_init(acpi_ac_init);

7:module_exit(acpi_ac_exit);

观察多个例子发现,出口函数和返回值都为void。

2.编写出口函数的内核模块

对于出口函数来说,数据类型为 void1+函数名+(void),再加上--exit 的说明,和入口函数的 init 相对应,放在--exit 的段里面:

出口(卸载)

Module_exit(卸载函数名);

Void__exit xxx_func(void)

因此在书写内核模块时,定义一个--init 类型的函数和--exit 类型的函数传入进服务器,最后再注册一个 GPL 申明。

 

四、编写内核模块的准备工作

编写内核模块,需要用到 module_exit 、module_init 和 module_LICENSE 的宏,也由内核提供。

因此需要寻找内核在哪里申明或者定义了这些函数,如果一个宏函数在一个地方进行定义,在同一个地方进行申明,那么则称这个宏函数为该区域函数。

进入 Linux 内核中,找到 include 中,有一个 Linux,在 Linux 中找到 init。

如图:

image.png

在里面寻找 module_init:

madte tnle/I eithee cslledduring do_initcalls() (ff

Insertion time (1f Therecanon

be one per

delvereit entrvnodnt

unct onto be runmhen driver Is reaaved

code

driver is staticelly

eeendled the fect.

There be one per

观察发现,该函数使用了函数宏。因此在使用这俩个函数的时候,应该包含这个同介 。

关于 module-LICENSE ,则存在与 Linux 中。

image.png

综上,找到了内核模块的同文件。


找到了内核模块的同文件和函数类型之后,即可以编写一个内核模块:

1.入口(加载)

module init(入口函数名);int initxxx func(void)

2.出口(卸载)

module exit(卸载函数名);void exitXXXfunc(void)

3.GPL 协议申明

MODULELICENSE("GPL");

 

五、编写内核模块

在编写的时候,可使用任意一个编辑器进行编辑,编写完成之后,则有了.c 即源文件。这里以 source insight 为例。

新建一个 demo.c:创建好文件之后保存好。

1. 第一步:包含源文件:

1:#include

2: #include

3:

4:

5:

6:module_init();

7:module_exit();

8:MODULE_LICENSE(GPL);

1:#include

2: #include

这俩个同文件调用之后,接下来调用同文件里面定义的宏。

定义宏分为三要素:入口函数,出口函数和申明。

1:#include

2: #include

3:

4:

5:

6:module_init();

7:module_exit();

8:MODULE_LICENSE(GPL);

接下来需要对 module_exit 和 module_init 写一个入口和出口函数,取名为“dmo__init”,再在前面加上__init 的说明

有返回值,用 return 返回0,再上传到 module.init 的宏里面。

对于__exit 类型,同理:

1:#include

2: #include

3:

4:

5:int _init demo_init(void)

6:{

7:     return 0

8: }

9:

10:

11:

12:

13:module_init();

14:module_exit();

15:MODULE_LICENSE(GPL);

到这步为止,内核模块编写完成,接下来剩下来的内容需要在 demo_init 和 demo_exit 里面去编写完成。

检查 demo 是否正在执行,加上一条打印语句进行调试。

使用 printk(),格式化输出,不定参数。打印级别为八种,如果打印级别比控制级别高的话,可以直接打印出来;如果比控制级别低,不打印,放在消息日志里面。 

同时打印级别可以省略掉不写,printk 可以直接当做 printf 去进行使用。输入语句为:

Printk(”---%s---%s---%d---\m,__,__func__,__(LINE__);

退出的时候也需要进行打印,在退出时可以看到 demo.init 被调用,在卸载时,demo.exit 被调用。

#include

#include

int _init demo init(void)

printk -%s---%s---%d---\n", FILE func LINE

return e;

I

rvoid exitdemo_exit(void)

printk("---%s---%s---%d---\n", FILE func LINE

module_init(demo_init);

moduleexit(demo_exit);

MODULELICENSE("GPL")

以上,内核模块全部编写完成。

相关文章
|
2月前
|
Linux
探索Linux操作系统的内核模块
本文将深入探讨Linux操作系统的核心组成部分——内核模块,揭示其背后的工作机制和实现方式。我们将从内核模块的定义开始,逐步解析其加载、卸载以及与操作系统其他部分的交互过程,最后探讨内核模块在系统性能优化中的关键作用。
|
12月前
|
存储 编译器 开发者
内核模块(下)
内核模块(下)
135 0
|
12月前
|
编译器 Linux 开发者
内核模块(上)
内核模块
72 0
|
Linux KVM 虚拟化
Linux内核模块
在模块A编译好后会生成符号表文件Module.symvers, 里面有函数地址和函数名对应关系,把这个文件拷贝到需要调用的模块B的源代码下,替换模块B的该文件。 然后重新编译B模块.这样就能够让模块B调用模块A的函数,以后加载模块顺序也必须先A后B,卸载相反。
Linux内核模块
|
网络协议 物联网 Linux
内核模块4 | 学习笔记
快速学习内核模块4
105 0
内核模块4 | 学习笔记
|
Ubuntu 物联网 编译器
内核模块3 | 学习笔记
快速学习内核模块3
114 0
内核模块3 | 学习笔记
|
Linux
linux内核模块指北
linux内核模块指北
62 0
|
缓存 IDE Linux
16.4 Linux内核(内核模块)的加载
GRUB 加载了内核之后,内核首先会再进行二次系统的自检,而不一定使用 BIOS 检测的硬件信息。这时内核终于开始替代 BIOS 接管 Linux 的启动过程了。
191 0
16.4 Linux内核(内核模块)的加载
|
Linux
16.16 Linux内核模块管理
Linux 的内核会在启动过程中自动检验和加载硬件与文件系统的驱动。一般这些驱动都是用模块的形式加载的,使用模块的形式保存驱动,可以不直接把驱动放入内核,有利于控制内核大小。
118 0
16.16 Linux内核模块管理
|
开发框架 Ubuntu Unix
内核模块-基本概念
内核模块-基本概念
251 0