day(2,3)-内核模块

news/2024/10/30 19:34:44/

内核模块上

主要内容

向内核添加新功能

内核模块基础代码讲解

内核模块多源文件编程

内核模块信息宏

一、向内核添加新功能

1.1 静态加载法:

即新功能源码与内核其它代码一起编译进uImage文件内

Kconfig是make menuconfig的界面配置文件

1.2动态加载法:

新功能源码单独作为模块编译

内核模块下

模块传参

模块依赖

模块编程与应用编程的比较

内核接口头文件查询

一、模块传参

module_param(name,type,perm);//将指定的全局变量设置成模块参数name:全局变量名
type:使用符号      实际类型                传参方式bool	     bool           insmod xxx.ko  变量名=0 或 1invbool      bool           insmod xxx.ko  变量名=0 或 1charp        char *         insmod xxx.ko  变量名="字符串内容"short        short          insmod xxx.ko  变量名=数值int          int            insmod xxx.ko  变量名=数值long         long           insmod xxx.ko  变量名=数值ushort       unsigned short insmod xxx.ko  变量名=数值uint         unsigned int   insmod xxx.ko  变量名=数值ulong        unsigned long  insmod xxx.ko  变量名=数值
perm:给对应文件 /sys/module/name/parameters/变量名 指定操作权限(一般为0664)#define S_IRWXU 00700#define S_IRUSR 00400#define S_IWUSR 00200#define S_IXUSR 00100#define S_IRWXG 00070#define S_IRGRP 00040#define S_IWGRP 00020#define S_IXGRP 00010#define S_IRWXO 00007#define S_IROTH 00004#define S_IWOTH 00002  //不要用 编译出错#define S_IXOTH 00001

数组传递

module_param_array(name,type,&num,perm);
/*
name、type、perm同module_param,type指数组中元素的类型
&num:存放数组大小变量的地址,可以填NULL(确保传参个数不越界)传参方式 insmod xxx.ko  数组名=元素值0,元素值1,...元素值num-1 
*/ 
#include <linux/module.h>
#include <linux/kernel.h>int gx = 10;
char *gstr="chris love ljx";
int garr[5]={1,2,3,4,5};module_param(gx,int,0664);
module_param(gstr,charp,0664);
module_param_array(garr,int,NULL,0664);int __init testparam_init(void)
{int i = 0;printk("gx = %d\n",gx);printk("gstr = %s\n",gstr);for(i = 0;i<5;i++){printk("%d",garr[i]);}printk("\n");return 0;
}void __exit testparam_exit(void)
{printk("test1 will exit\n");
}
MODULE_LICENSE("GPL");
module_init(testparam_init);
module_exit(testparam_exit);

传递参数 

 二、模块依赖

modulea.c

#include <linux/module.h>
#include <linux/kernel.h>int ga = 6;
EXPORT_SYMBOL(ga);int __init modulea_init(void)
{printk("ga = %d\n",ga);return 0;
}void __exit modulea_exit(void)
{printk("modulea will exit\n");
}
MODULE_LICENSE("GPL");
module_init(modulea_init);
module_exit(modulea_exit);

moduleb.c

#include <linux/module.h>
#include <linux/kernel.h>extern int ga;int __init moduleb_init(void)
{printk("In moduleb_init,ga = %d\n",ga);return 0;
}void __exit moduleb_exit(void)
{printk("moduleb will exit\n");
}
MODULE_LICENSE("GPL");
module_init(moduleb_init);
module_exit(moduleb_exit);

Makefile

ifeq ($(KERNELRELEASE),)ifeq ($(ARCH),arm)
KERNELDIR ?= /home/chris/Linux_4412/kernel/linux-3.14
ROOTFS ?= /opt/4412/rootfs
else
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
endif
PWD := $(shell pwd)modules:$(MAKE) -C $(KERNELDIR) M=$(PWD) modulesmodules_install:$(MAKE) -C $(KERNELDIR) M=$(PWD) modules INSTALL_MOD_PATH=$(ROOTFS) modules_installclean:rm -rf  *.o  *.ko  .*.cmd  *.mod.*  modules.order  Module.symvers   .tmp_versionselse
obj-m += modulea.o
obj-m += moduleb.oendif

两个依赖模块在不同文件夹时,需要将被依赖的模块先编译,将生成的Modele.symvers文件放到依赖模块的同路径,再编译

两个用于导出模块中符号名称的宏:

EXPORT_SYMBOL(函数名或全局变量名)

EXPORT_SYMBOL_GPL(函数名或全局变量名) 需要GPL许可证协议验证

使用导出符号的地方,需要对这些符号进行extern声明后才能使用这些符号

B模块使用了A模块导出的符号,此时称B模块依赖于A模块,则:

  1. 编译次序:先编译模块A,再编译模块B,当两个模块源码在不同目录时,需要:i. 先编译导出符号的模块A ii. 拷贝A模块目录中的Module.symvers到B模块目录 iii. 编译使用符号的模块B。否则编译B模块时有符号未定义错误

  2. 加载次序:先插入A模块,再插入B模块,否则B模块插入失败

  3. 卸载次序:先卸载B模块,在卸载A模块,否则A模块卸载失败三、内核空间和用户空间

三、内核空间和用户空间

为了彻底解决一个应用程序出错不影响系统和其它app的运行,操作系统给每个app一个独立的假想的地址空间,这个假想的地址空间被称为虚拟地址空间(也叫逻辑地址),操作系统也占用其中固定的一部分,32位Linux的虚拟地址空间大小为4G,并将其划分两部分:

  1. 0~3G 用户空间 :每个应用程序只能使用自己的这份虚拟地址空间

  2. 3G~4G 内核空间:内核使用的虚拟地址空间,应用程序不能直接使用这份地址空间,但可以 通过一些系统调用函数与其中的某些空间进行数据通信

实际内存操作时,需要将虚拟地址映射到实际内存的物理地址,然后才进行实际的内存读写

四、执行流

执行流:有开始有结束总体顺序执行的一段独立代码,又被称为代码上下文

计算机系统中的执行流的分类:

执行流:

  1. 任务流--任务上下文(都参与CPU时间片轮转,都有任务五状态:就绪态 运行态 睡眠态 僵死态 暂停态)

    1. 进程

    2. 线程

      1. 内核线程:内核创建的线程

      2. 应用线程:应用进程创建的线程

  2. 异常流--异常上下文

    1. 中断

    2. 其它异常

应用编程可能涉及到的执行流:

  1. 进程

  2. 线程

内核编程可能涉及到的执行流:

  1. 应用程序自身代码运行在用户空间,处于用户态 ----------------- 用户态app

  2. 应用程序正在调用系统调用函数,运行在内核空间,处于内核态,即代码是内核代码但处于应用执行流(即属于一个应用进程或应用线程) ---- 内核态app

  3. 一直运行于内核空间,处于内核态,属于内核内的任务上下文 --------- 内核线程

  4. 一直运行于内核空间,处于内核态,专门用来处理各种异常 --------- 异常上下文

五、模块编程与应用编程的比较

六、内核接口头文件查询

大部分API函数包含的头文件在include/linux目录下,因此:

  1. 首先在include/linux 查询指定函数:grep 名称 ./ -r -n

  2. 找不到则更大范围的include目录下查询,命令同上

    例:

grep MODULE_AUTHOR ./ -r -n


http://www.ppmy.cn/news/65827.html

相关文章

18 KVM管理虚拟机-虚拟机生命周期总体介绍

文章目录 18 KVM管理虚拟机-虚拟机生命周期总体介绍18.1 概述18.2 虚拟机状态18.3 状态转换18.4 虚拟机标识 18 KVM管理虚拟机-虚拟机生命周期总体介绍 18.1 概述 为了更好地利用硬件资源&#xff0c;降低成本&#xff0c;用户需要合理地管理虚拟机。本节介绍虚拟机生命周期过…

tpm2-tools源码分析之tpm2_unseal.c(2)

接前一篇文章&#xff1a;tpm2-tools源码分析之tpm2_unseal.c&#xff08;1&#xff09; 本文对tpm2_unseal.c中的tpm2_tool_onstart函数进行详细解析。 先再次贴出该函数源码&#xff1a; static bool tpm2_tool_onstart(tpm2_options **opts) {static const struct option …

算法修炼之练气篇——练气十六层

博主&#xff1a;命运之光 专栏&#xff1a;算法修炼之练气篇 前言&#xff1a;每天练习五道题&#xff0c;炼气篇大概会练习200道题左右&#xff0c;题目有C语言网上的题&#xff0c;也有洛谷上面的题&#xff0c;题目简单适合新手入门。&#xff08;代码都是命运之光自己写的…

《花雕学AI》新版必应 Bing 登场:轻松注册,一站式搜索、聊天与绘画应有尽有

引言&#xff1a; 你是否曾经在网上搜索信息时感到困惑或沮丧&#xff1f;你是否曾经想要在网上创造一些有趣或有用的内容&#xff0c;却不知道从何开始&#xff1f;你是否曾经想要用文字描述一个图像&#xff0c;却无法找到合适的图片&#xff1f;如果你的答案是肯定的&#x…

【JS】1680- 重学 JavaScript API - Beacon API

❝ 前期回顾&#xff1a;1.Page Visibility API 2.Broadcast Channel API ❞ 1. 什么是 Beacon API 1.1 概念介绍 Beacon API 是 HTML5 提供的一种新的浏览器 API&#xff0c;可以用于在浏览器后台异步地发送数据&#xff0c;而不影响当前页面的加载和性能。通过 Beacon API&am…

安全访问服务边缘 (SASE) 技术的优缺点及工作原理

随着企业向云迁移&#xff0c;移动性成为常态&#xff0c;网络和安全解决方案必须相应地发展。安全访问服务边缘 &#xff08;SASE&#xff09; 在此处进入图片。SASE 是一个新兴的技术类别&#xff0c;旨在提供特定的网络安全功能。 安全访问服务边缘 &#xff08;SASE&#…

qemu-基础篇——ARM 链接过程分析(六)

文章目录 ARM 链接过程分析源文件global_bss_file.cglobal_data_fle.cglobal_function_file.cglobal_rodata_file.cmain.c 链接文件 link.lds编译命令及反汇编命令解析 .o 文件global_bss_file.oglobal_data_fle.oglobal_function_file.oglobal_rodata_file.omain.o 链接观察链…

网络基础学习:osi网络七层模型

osi网络七层模型 什么是OSI&#xff0c;什么是ISO?为什么ISO要提出OSI网络七层模型&#xff1f;OSI七层的划分以及具体内容第七层 应用层第六层 表示层第五层 会话层第四层 传输层第三层 网络层第二层 数据链路层第一层 物理层 每一层与设备的对应关系 什么是OSI&#xff0c;什…