uboot通过bootargs传递内核中的模块传递参数
创始人
2024-04-25 07:42:47
0

前言

bootargs是uboot向内核传递参数时使用的,本次我们要验证的是bootargs向内核启动后加载的模块传递的参数,真正的跨过山和大海。跟着我的脚步,来一次bootargs之旅。

这是一个综合性,系统性很强的实例验证,要做这个实验,

首先能够进入uboot命令行。

其次相关的系统内核源码。

第三,具备编译一个模块的环境。

一 编写模块

这是一个platform驱动。可以接受参数。分别是int,charp,bool三种类型。且支持设备树。

源码gebageba.c

#include 
#include 
#include 
#include 
#include 
#include #define MYDEBUG(format,...)	printk("%s - %d:"format"\n",\__func__,__LINE__,##__VA_ARGS__)static int int_para = 10086;
module_param_named(int_para_name,int_para,int, 0644);static char* char100 = "who are you";
module_param_named(char100_name,char100,charp,0644);static bool isboy = true;
MODULE_PARM_DESC(isboy, "Yes,yes,A boy,not a bird man");
module_param_named(isboy_name, isboy, bool, 0644);static int isp_dev_probe(struct platform_device *pdev)
{MYDEBUG("int_para = %d",int_para);MYDEBUG("char100 = %s",char100);MYDEBUG("isboy = %d",isboy);return 0;
}
static int isp_dev_remove(struct platform_device *pdev)
{MYDEBUG("bye bai");return 0;
}static const struct of_device_id isp_dt_ids[] = {{ .compatible = "helloworld", },{ /* sentinel */ }
};MODULE_DEVICE_TABLE(of, isp_dt_ids);static struct platform_driver isp_platform_driver = {.driver = {.name = "gebageba",.of_match_table = of_match_ptr(isp_dt_ids),},.probe	= isp_dev_probe,.remove	= isp_dev_remove,
};module_platform_driver(isp_platform_driver);MODULE_LICENSE("GPL");
MODULE_AUTHOR("lkmao");
MODULE_DESCRIPTION("Balabala ... Balala ... Balala");

二 配置设备树

在设备树根节点下添加如下所示的内容,这么正式的代码,相信读者一定知道是哪一行,没错就是hello22,为什么是这个名字,当然不是因为第22条军规,主要是我自己在设备树里测试代码太多了,给一个垃圾名字,让看见的人明白,这是个垃圾。可以随便删。

  / {
/*略*/hello22{compatible = "helloworld";};
/*略*/
};

三 设置Kconfig和Makefile

1 在drivers目录添加子目录,并修改Makefile

在内核的driver目录创建文件夹

lkmao@ubuntu:~/imx/linux/linux-imx/drivers$ mkdir gebageba
lkmao@ubuntu:~/imx/linux/linux-imx/drivers$

修改drivers目录的Makefile,添加gebageba这个子目录,修改方式,在drivers/Makefile文件最底下,添加如下内容。

obj-y       += gebageba/

2  创建并编写自己的Makefile

下面的操作是在新的gebageba目录操作的,然后创建Kconfig和Makefile文件 

lkmao@ubuntu:~/imx/linux/linux-imx/drivers/gebageba$ touch Kconfig Makefile
lkmao@ubuntu:~/imx/linux/linux-imx/drivers/gebageba$ ls -lsh
总用量 0
0 -rw-rw-r-- 1 lkmao lkmao 0 12月 17 16:19 Kconfig
0 -rw-rw-r-- 1 lkmao lkmao 0 12月 17 16:19 Makefile
lkmao@ubuntu:~/imx/linux/linux-imx/drivers/gebageba$

编写Makefile文件 

obj-m = gebageba.c

 3  创建并编写自己的Kconfig

然后,就是让make menuconfig时,能够找到我们的新驱动,并能够配置它:修改drivers/Kconfig文件,最后一行endmenu前面添加source "drivers/gebageba/Kconfig",如下图所示:

 修改我们自己的drivers/gebageba/Kconfig,写的还是挺正规的。

config LKMAO_GEBAGEBAtristate "this is a module test: parameter send form uboot to this module"default MhelpThis macro very good.

保存,执行make menuconfig,如下图所示,有个绿色的加号,以前还真没注意到。

 

 选项走过来以后绿色的加号就不见了。

 Y变成*,M变成M,N表示不选,我们输入M,当做模块。配置完,在.config文件中搜索新的配置项,如下所示,配置成功了。

lkmao@ubuntu:~/imx/linux/linux-imx$ cat .config | grep GEBAGEBA
CONFIG_LKMAO_GEBAGEBA=m
lkmao@ubuntu:~/imx/linux/linux-imx$

修改drivers/gebageba/Makefile文件,让它可配置:

obj-$(CONFIG_LKMAO_GEBAGEBA) = gebageba.o

 make modules_install INSTALL_MOD_PATH=tmp,

输出结果中看到,我们的模块被编译了。

 

 

三 设置bootargs

模块名字叫gebageba。参数名字叫啥了?忘记了,没关系使用modinfo + 模块名字 命令查看:

lkmao@ubuntu:~/imx/linux/linux-imx/drivers/gebageba$ modinfo gebageba.ko
filename:       /home/lkmao/imx/linux/linux-imx/drivers/gebageba/gebageba.ko
license:        GPL
srcversion:     73C63980927DB0B2865878D
alias:          of:N*T*Chelloworld*
depends:
intree:         Y
vermagic:       4.1.15 SMP preempt mod_unload modversions ARMv7 p2v8
parm:           int_para_name:int
parm:           char100_name:charp
parm:           isboy:Yes,yes,A boy,not a bird man
parm:           isboy_name:bool
lkmao@ubuntu:~/imx/linux/linux-imx/drivers/gebageba$

为了最大程度让实验具备可复制性,我们只修改int类型的参数:在uboot中修改bootargs参数

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw gebageba.int_para_name=10010'

 修改完毕后,记得使用saveenv保存新参数

四 验证模块和设备树

下面的操作,具体情况具体分析,总之就是想办法把模块送到板子中。在这里还是有很多学问的,作为初学者,能避开的难点就避开。除非是真的很聪明,很天才。反正我是比较蠢的那种。

lkmao@ubuntu:~/imx/linux/linux-imx$ sudo scp tmp/modules.tar root@192.168.0.33:/lib/modules
The authenticity of host '192.168.0.33 (192.168.0.33)' can't be established.
RSA key fingerprint is SHA256:yyVGvCUidWhwOAXI2+q+vlb9lAgyr0URCK6WBr/uaqY.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.0.33' (RSA) to the list of known hosts.
modules.tar                                                                                                 100% 4040KB   4.0MB/s   00:01
lkmao@ubuntu:~/imx/linux/linux-imx$

如下所示:我们的模块已经站在哪里等着了。

root@hehe:/lib/modules/4.1.15/kernel/drivers/gebageba# ls
gebageba.ko
root@hehe:/lib/modules/4.1.15/kernel/drivers/gebageba#

然后就是看看设备树是否准备好,设备树在哪里,不是在flash里吗?在根文件系统中有对应的虚拟文件系统,就是目录/sys/firmware/devicetree。我们新加的节点是hello22。如下所示,设备树也就绪了。

root@hehe:/sys/firmware/devicetree/base/hello22# cat compatible ;echo
helloworld
root@hehe:/sys/firmware/devicetree/base/hello22# cat name ;echo
hello22
root@hehe:/sys/firmware/devicetree/base/hello22# pwd
/sys/firmware/devicetree/base/hello22
root@hehe:/sys/firmware/devicetree/base/hello22#

 五 开始测试

下图所示,记住这三个_name结尾的字符串,这三就是模块参数在外部看到的名字。 

1 修改int类型数据

就是在原有的bootargs的基础上添加gebageba.int_para_name=10010,gebageba是模块名字,int_para_name是参数名字,10010是新设置的值。

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw gebageba.int_para_name=10010'

 从前面的代码可知,默认值是10086.

启动后,值变成10010,就算测试成功。下图为测试结果

好了,这应该就算测试成功了,下面的内容可以不用看了。 

2 修改charp类型数据 传输带空格的参数有错误

 就是在原有的bootargs的基础上添加gebageba.char100_name="Ku lu,Ku lu",gebageba是模块名字,char100_name是参数名字,"Ku lu,Ku lu"是新设置的值。

setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw gebageba.char100_name="Ku lu,Ku lu"'

 从前面的代码可知,默认值是who are you。

下图为测试结果,结果只有一个Ku,难道是因为空格

 这里需要看下内核源码的parse_args函数怎么实现的。

Params.c (kernel)文件

char *parse_args(const char *doing,char *args,const struct kernel_param *params,unsigned num,s16 min_level,s16 max_level,int (*unknown)(char *param, char *val, const char *doing))
{char *param, *val;/* Chew leading spaces */args = skip_spaces(args);if (*args)pr_debug("doing %s, parsing ARGS: '%s'\n", doing, args);while (*args) {int ret;int irq_was_disabled;args = next_arg(args, ¶m, &val);/* Stop at -- */if (!val && strcmp(param, "--") == 0)return args;irq_was_disabled = irqs_disabled();ret = parse_one(param, val, doing, params, num,min_level, max_level, unknown);if (irq_was_disabled && !irqs_disabled())pr_warn("%s: option '%s' enabled irq's!\n",doing, param);switch (ret) {case -ENOENT:pr_err("%s: Unknown parameter `%s'\n", doing, param);return ERR_PTR(ret);case -ENOSPC:pr_err("%s: `%s' too large for parameter `%s'\n",doing, val ?: "", param);return ERR_PTR(ret);case 0:break;default:pr_err("%s: `%s' invalid for parameter `%s'\n",doing, val ?: "", param);return ERR_PTR(ret);}}/* All parsed OK. */return NULL;
}

在这个函数中调用了skip_spaces。

/*** skip_spaces - Removes leading whitespace from @str.* @str: The string to be stripped.** Returns a pointer to the first non-whitespace character in @str.*/
char *skip_spaces(const char *str)
{while (isspace(*str))++str;return (char *)str;
}

可能不是这里,总之,就是不能出现空格,修改booargs如下所示将空格换成\x20

=> setenv bootargs "console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw gebageba.char100_name='Ku\\x20lu,Ku\\x20lu'"
=> printenv bootargs
bootargs=console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw gebageba.char100_name=Ku\x20lu,Ku\x20lu
=>

显然,这并非我们想要的结果;传参文档位于Documentation/kernel-parameters.txt,我们去研究研究。还真有,

Double-quotes can be used to protect spaces in values, e.g.:param="spaces in here"

 这里介绍了rootwait的作用:

rootwait	[KNL] Wait (indefinitely) for root device to show up.Useful for devices that are detected asynchronously(e.g. USB and MMC devices).
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw gebageba.char100_name=! gebageba.char100_name=Ku" "lu,Ku" "lu'

卸载模块,然后手动加载模块传递参数,这样是没问题的。

root@hehe:~# rmmod gebageba
[   21.994268] isp_dev_remove - 32:bye bai
root@hehe:~# modprobe gebageba char100_name='ku'
[   44.434610] isp_dev_probe - 25:int_para = 10010
[   44.439174] isp_dev_probe - 26:char100 = ku
[   44.447188] isp_dev_probe - 27:isboy = 1
root@hehe:~# rmmod gebageba
[   48.250783] isp_dev_remove - 32:bye bai
root@hehe:~# modprobe gebageba char100_name='ku la'
[   51.494024] isp_dev_probe - 25:int_para = 10010
[   51.498586] isp_dev_probe - 26:char100 = ku la
[   51.503037] isp_dev_probe - 27:isboy = 1
root@hehe:~# rmmod gebageba
[  100.860819] isp_dev_remove - 32:bye bai
root@hehe:~#
root@hehe:~# modprobe gebageba char100_name="ku la"
[  110.336387] isp_dev_probe - 25:int_para = 10010
[  110.340949] isp_dev_probe - 26:char100 = ku la
[  110.349143] isp_dev_probe - 27:isboy = 1
root@hehe:~#

 暂时搁置

 六 使用转义字符输出空格

首先看下转义字符表:

 测试代码:

#include 
int main()
{printf("hello\x20world\n");
}

测试结果:没问题\x20确实被转义为空格了。 

lkmao@ubuntu:~/imx/linux/linux-imx/drivers/gebageba$ ./a.out
hello world
lkmao@ubuntu:~/imx/linux/linux-imx/drivers/gebageba$

小结

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
AWSECS:哪种网络模式具有... 使用AWS ECS中的awsvpc网络模式来获得最佳性能。awsvpc网络模式允许ECS任务直接在V...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...