linux内核模块

600 阅读3分钟

「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战

linux内核模块

模块化的 允许在内核运行过程中动态的插入或删除代码

模块组成:模块加载函数、模块卸载函数、模块许可申明、模块参数(可选)等可选项

#include <linux/init.h>
#include <linux/module.h>
#include <kernel.h>
/* 
​
 * hello_init- 初始化函数,当模块装载时被调用,如果成功装载返回0,否则返回非零值
   */
   static int __init hello_init (void)
   {
   printk(KERN_ALERT "What do we eat at lunch?\n");            /* 用于输出的函数是内核空间的printk(),printf用于用户空间 */
   return 0;
   }
   /* 
 * hello_exit-退出函数,当模块卸载时被调用
   */
   static void __exit hello_exit (void)
   {
   printk(KERN_ALERT "Xibei Lou beef noodle!\n");
   }
/*
 * hello_init是函数的入口点,它通过module_init()例程注册到系统中,在内核装载时被调用
 * module_init实际上不是一个真正的函数调用,而是一个宏调用,唯一的参数是模块的初始化函数
 */
module_init (hello_init);
​
/*
 * hello_exit是函数的出口函数,它通过module_exit()例程注册到系统中,在内核卸载时被调用
 */
module_exit (hello_exit);
​
MODULE_LICENSE ("GPL")  /* 指定模块的版权,描述内核模块的许可权限,一般情况应遵循GPL兼容许可证 */
MODULE_AUTHOR ("Guo Liting");          /* 指定代码的作者 */
MODULE_DESCRPTION ("Lunch");         /* 指定模块的简要描述 */

MakeFile

在linux中使用make命令来编译程序 make命令执行顺序为

hello:hello.c
    gcc -o hello hello.c
clean:
    rm -f hello

obj-y += hello_world.o 表示由hello_world.c或hello_world.s文件无条件编译得到hello_world.o并链接进内核 obj-m += hello_world.o 表示该文件要作为模块编译,obj-n 形式的目标不会被编译 obj-(CONFIGHELLOWORLD)+=helloworld.o根据makemenuconfig后生成的config文件的CONFIG量来决定文件的编译方式,y/mobj(CONFIG_HELLO_WORLD) += hello_world.o 根据 make menuconfig 后生成的 config 文件的 CONFIG_ 变量来决定文件的编译方式,y/m obj-(CONFIG_HELLO_WORLD_DIR) += hello_world 当 CONFIG_HELLO_WORLD_DIR 的值为 y 或 m 时,kbuild将会把目录列入向下迭代的目标中 当一个模块由多个文件组成时

Kconfig

内核配置脚本文件

insmod rmmod 内核模块的加载卸载

字符设备驱动程序

字符设备开发

  1. 确定主设备号和次设备号

  2. 实现字符驱动程序

    实现file_operations结构体

    实现初始化函数,注册字符设备

    实现销毁函数,释放字符设备

  3. 创建设备文件节点

主设备号:内核识别一个设备的标识

次设备号:由内核使用,用于正确确定设备文件所指的设备。

设备编号:dev_t类型(32位)

//动态分配主设备号
#include <linux/fs.h>
int  alloc_chrdev_resion(dev_t *dev,unsigned int firstminor,count,char *name)
//释放设备号
void  unregister_chrdev_region(dev_t first, unsigned int count);

cdev结构体

操作cdev结构体的函数

file_operations结构体

字符驱动和内核的接口 在include/linux/fs.h定义

字符驱动只要实现一个file_operations结构体并注册到内核中,内核就有了操作设备的能力。

file_operations的主要成员: struct module *owner: 指向模块自身 open:打开设备 release:关闭设备 read:从设备上读数据 write:向设备上写数据 ioctl:I/O控制函数 llseek:定位读写指针 mmap:映射设备空间到进程的地址空间

添加驱动程序到内核中

在Linux内核中增加程序需要完成以下3项工作。 将编写的源代码复制到Linux内核源代码的相应目录。 在目录的Kconfig文件中增加新源代码对应项目的编译配置选项。 在目录的Makefile文件中增加对新源代码的编译条目。

修改新增目录的父目录的Kconfig和Makefile 在drivers/Kconig中加入:source "drivers/test/Kconfig“ 在drivers/Makefile中加入:obj-$(CONFIG_TEST) += test/ 在arch/arm/Kconfig里加入:source “drivers/test/Kconfig

修改本目录和父目录的Kconfig和Makefile文件

minimod打印串口log的方法

dmesg -w | grep abx