linux中模块的构建,传参,和printk函数的简单使用

静态编译,动态加载
应用想访问内核需要通过系统调用

驱动:
1.模块(打包,加入内核)
2.内核机制
3.操作硬件

在Kconfig里面配置menuconfig的时候,不同的类型会在图形化界面的终端显示不用的配置选项:
bool CONFIG_HELLO []hello_driver 两态
tristate CONFIG_HELLO <>hello_driver 三态的 空 * M
string/int CONFIG_HELLO ()hello_driver 相当于宏替换 (dest)hello_driver ---> 最后在.config中的到的结果就是hello_driver = dest,这个是字符串的格式

函数模块化编写,可卸载:
下面是函数:hello_module.c

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL"); 模块认证,不写这条语句,最后内核会抱怨的

static int __init hello_init(void) //通过下面的module,最终内核会解释这条语句为 init_module(),内核执行的时候找的就是这个函数名
{ 函数前面加了--init表示执行一次后对段内容的优化,优化内存,节省空间
printk("hello_init ! \n");
return 0;
}

static void __exit hello_exit(void) //通过下面的module,最终内核会解释这条语句为 cleanup_module(),执行的时候内核找的就是这个函数名
{
printk("hello_exit ! \n");
}

/* module_init:
* 1. static compile : set "hello_init" to .init section
* 2. dynamic loadable module: hello_init named init_module
*/
module_init(hello_init);
module_exit(hello_exit);

MODULE_AUTHOR("[email protected]"); 标注一些信息
MODULE_DESCRIPTION("just for test!");

对应于上面的makefile的编写:

MOD_NAME = hello_module

obj-m = $(MOD_NAME).o

#KERN_DIR = /home/linux/linux-2.6.35-farsight
KERN_DIR = /lib/modules/$(shell uname -r)/build

all:
make -C $(KERN_DIR) M=$(shell pwd) modules

clean:
rm -rf *.o *.ko *.mod.c *.order *.symvers .*.cmd .*versions

backup:
tar cvf ../$(MOD_NAME).tar.gz ../$(MOD_NAME)
cp ../$(MOD_NAME).tar.gz /mnt/hgfs/ubuntu_share

上面c文件编译过后会生成.ko文件:用下面语句可执行:
1.make module
2.sudo insmod hello_module.ko 调用后自动运行驱动程序
3.sudo dmesg -C 清空之前缓存里面的数据,不然会接着上次打印的结果继续打印,干扰对代码的解读
4.dmesg 查看代码运行的结果
5.rmmod hello_module 注意这里不加.ko
6.lsmod 查看模块

当想看到hello_module.ko的详细信息的时候,可以用下面的命令:
modinfo hello_module.ko

内核函数里面的传参:hello_param.c

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

static int m; 想要传参的变量
static int n;

module_param(m, int, 0600); 这里是对参数属性的一些定义:int类型,0600是权限,读写权限
module_param(n, int, 0200);

static int __init hello_init(void)
{
printk("hello_init ! \n");
printk("m = %d : n = %d \n", m, n);
return 0;
}

static void __exit hello_exit(void)
{
printk("hello_exit ! \n");
printk("m = %d : n = %d \n", m, n);
}

/* module_init:
* 1. static compile : set "hello_init" to .init section
* 2. dynamic loadable module: hello_init named init_module
*/
module_init(hello_init);
module_exit(hello_exit);

MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("just for test!");

针对上面函数写的makefile:
MOD_NAME = hello_param

obj-m = $(MOD_NAME).o

#KERN_DIR = /home/linux/linux-2.6.35-farsight
KERN_DIR = /lib/modules/$(shell uname -r)/build

all:
make -C $(KERN_DIR) M=$(shell pwd) modules

clean:
rm -rf *.o *.ko *.mod.c *.order *.symvers .*.cmd .*versions

backup:
tar cvf ../$(MOD_NAME).tar.gz ../$(MOD_NAME)
cp ../$(MOD_NAME).tar.gz /mnt/hgfs/ubuntu_share

编译上面的代码后,传参命令如下:
1.sudo insmod hello_param.ko m=1234 n=4321
2.dmesg

查看传入内核的参数,可用下面的命令查找:
1.cd /sys/module/hello_param/parametes/
2.ls
3.sudo cat 查看你先看的参数

内核函数的导出:

一个c文件里面的函数在另一个函数里面调用:
下面是C文件的脚本,可参考:

函数提供者:hello_export.c
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL"); 内核遵循的认证

void common_func(void) 我们用到的导出函数
{
printk("common_func! \n");
}
EXPORT_SYMBOL_GPL(common_func); //EXPORT_SYMBOL 在这里将函数导出,前面加了GPL表示只有遵循GPL认证的模块可以使用这个函数

static int __init hello_init(void) 注意这个函数的返回值是int型的
{
printk("hello_init ! \n");
return 0;
}

static void __exit hello_exit(void) 这个函数的返回值必须是void类型的
{
printk("hello_exit ! \n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("just for test!");

函数使用者:hello_import.c

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

extern void common_func(void); 使用者先申明一下

static int __init hello_init(void)
{
common_func(); 在这里调用了这个函数
printk("hello_init ! \n");
return 0;
}

static void __exit hello_exit(void) 注意前面--exit是优化的作用,一般情况下都会加上的
{
printk("hello_exit ! \n");
}

module_init(hello_init);
module_exit(hello_exit);

MODULE_AUTHOR("[email protected]"); 标明作者的信息
MODULE_DESCRIPTION("just for test!"); 模块的描述

Makefile的编写:

MOD_NAME = hello_export

obj-m = $(MOD_NAME).o
obj-m += hello_import.o

#KERN_DIR = /home/linux/linux-2.6.35-farsight
KERN_DIR = /lib/modules/$(shell uname -r)/build 注意这边路径的编写,因为最后得到的.ko文件需要依赖编译的内核版本,这里解决不同版本的编译运行问题,值得学习

all:
make -C $(KERN_DIR) M=$(shell pwd) modules 跳到对应目录执行Makefile

clean:
rm -rf *.o *.ko *.mod.c *.order *.symvers .*.cmd .*versions

backup:
tar cvf ../$(MOD_NAME).tar.gz ../$(MOD_NAME)
cp ../$(MOD_NAME).tar.gz /mnt/hgfs/ubuntu_share

函数执行的时候:先加载提供者,后运行使用者

sudo insmod hello_export.ko
sudo insmod hello_import.ko

然后运行dmesg查看结果

导出后查看是否成功:cat /proc/kallsyms | grep common_func //下面会看到导出的函数
lsmod 也能看到函数的信息

卸载:先卸载使用者,后卸载提供者
sudo rmmod hello_import
sudo rmmod hello_export

内核打印函数printk(),hello_printk.c

#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>

MODULE_LICENSE("GPL");

static int __init hello_init(void)
{
printk(KERN_INFO "hello_info ! \n"); //KERN_INFO这里是打印优先级的设置
printk(KERN_NOTICE "hello notice ! \n"); //这些权限在内核include/linux/kerner.h里面可以查看
printk(KERN_ERR "hello_err ! \n");
printk(KERN_ALERT "hello_alert ! \n");
printk(KERN_WARNING "hello_warning ! \n");
return 0;
}

static void __exit hello_exit(void)
{
printk("hello_exit ! \n");
}

/* module_init:
* 1. static compile : set "hello_init" to .init section
* 2. dynamic loadable module: hello_init named init_module
*/
module_init(hello_init);
module_exit(hello_exit);

MODULE_AUTHOR("[email protected]");
MODULE_DESCRIPTION("just for test!");

上面C文件对应的makefile:

MOD_NAME = hello_printk

obj-m = $(MOD_NAME).o

#KERN_DIR = /home/linux/linux-2.6.35-farsight
KERN_DIR = /lib/modules/$(shell uname -r)/build

all:
make -C $(KERN_DIR) M=$(shell pwd) modules

clean:
rm -rf *.o *.ko *.mod.c *.order *.symvers .*.cmd .*versions

backup:
tar cvf ../$(MOD_NAME).tar.gz ../$(MOD_NAME)
cp ../$(MOD_NAME).tar.gz /mnt/hgfs/ubuntu_share

测试执行上面的程序的时候,需要在真正的终端下测试:ctrl+alt+f2进入终端,alt+f7退出终端
可以更改优先级:列如:
su
echo 8 4 1 7 > /proc/sys/kernel/printk //这样在第一个数组设置的对象里面打印的权限在小于8的都能被打印出来
insmod hello_printk.ko

***************************************************************************************************************************************************************
***************************************************************************************************************************************************************
***************************************************************************************************************************************************************
***************************************************************************************************************************************************************

时间: 2024-10-10 11:03:20

linux中模块的构建,传参,和printk函数的简单使用的相关文章

如何在Linux中使用sFTP上传或下载文件与文件夹

如何在Linux中使用sFTP上传或下载文件与文件夹 sFTP(安全文件传输程序)是一种安全的交互式文件传输程序,其工作方式与 FTP(文件传输协议)类似. 然而,sFTP 比 FTP 更安全;它通过加密 SSH 传输处理所有操作.在本文中,我们将向你展示如何使用 sFTP 上传/下载整个目录(包括其子目录和子文件). 作者:Aaron Kili来源:Linux中国|2017-03-09 14:42 移动端 收藏 分享 51CTO诚邀您9月23号和秒拍/国美/美团元专家一起聊智能CDN的优化之路

Linux中ftp不能上传文件/目录的解决办法

在linux中不能上传文件或文件夹最多的问题就是权限问题,但有时也不一定是权限问题了,像我就是空间不够用了,下面我来总结一些ftp不能上传文件/目录的解决办法 在排除用户组和权限等问题后,最可能引起ftp下文件无法上传并经常被忽略的因素就是硬盘空间已满,而导致硬盘空间满的问题多数是日志文件所占用的,例如mysql的日志会在不知不觉中变得十分庞大,直至占满剩余的硬盘空间. 解决办法: 1.定期手动清理或使用脚本清理mysql日志或其他相关日志文件. 2.关闭mysql日志(不推荐) 上面是空间有问

linux中使用lftp上传下载文件

lftp是linux中一款ftp服务器相比windows中的ftp显得要复杂不少了,下面我来总结一下lftp文件上传,文件下载,及文件查找等等相关命令吧. lftp连接的几种方法,最常用的是lftp [email protected],这样可以不用明文输入密码. 1.lftp [email protected] 回车 输入密码 2.lftp name:[email protected] 回车 3.lftp site 回车login 用户名 密码 4.lftp 回车 open site 回车 lo

vue中组件间的传参

1.父传子 父组件准备一个数据,通过自定义属性给子组件赋值,进行传递 在子组件中通过 props 属性来接收参数 <body> <div id="app"> <son passdata="msg"></son> </div> </body> <script> Vue.component('son', { template: '<div>父组件的数据为:{{ passdat

函数中对象名的传参形式

1. function setNumber($this,g,d,url){ var gid = $this.parent().attr("data-id"); var eids = $("#hidden").text(); var params = {}; params[g] = gid; //传参 params[d] = eidsl;//传参 if(eids==""){ layer.alert("勾选项为空,请选择"); r

Linux中使用SecureCRT上传、下载文件命令sz与rz用法实例

借助securtCRT,使用linux命令sz可以很方便的将服务器上的文件下载到本地,使用rz命令则是把本地文件上传到服务器 其中,对于sz和rz的理解与记忆我用了如下的方法(因为很多时候容易搞混):sz中的s意为send(发送),告诉客户端,我(服务器)要发送文件 send to cilent,就等同于客户端在下载.rz中的r意为received(接收),告诉客户端,我(服务器)要接收文件 received by cilent,就等同于客户端在上传. 注意:sz和rz命令需要服务器支持,如果提

linux驱动开发第二步 驱动模块传参(module_param函数使用)

在驱动的模块中声明一下你要传递的参数名称,类型和权限 module_param(变量的名称,类型,权限); 先上例子 #include <linux/init.h> #include <linux/module.h> static char *p_name = "Usr"; module_param(p_name, charp, S_IRUGO); MODULE_PARM_DESC(p_name, "This is a char * string.&q

linux中swap的构建

一.使用物理分区构建swap 1.分区 [[email protected] ~]# fdisk /dev/vdb Welcome to fdisk (util-linux 2.23.2). Changes will remain in memory only, until you decide to write them. Be careful before using the write command. Command (m for help): n Partition type: p  

Asp.Net中ObjectDataSource控件传参绑定数据

最近在实习,在上头交付的任务中,由于需要使用Asp.Net的ListView控件,因此必然得就使用了ObjectDataSource控件,由于在使用过程中,需要网页中的参数发送到后台后,运行该参数进行查询数据.这过程必然就牵涉到将参数传送给ObjectDataSource控件,然后在进行查询后的数据绑定.下面我们来看下这个过程是如何实现的: 1.创建一个WebForm页面,拖入ListView控件和ObjectDataSource控件 2.配置ObjectDataSource数据源按照以下步骤进