uboot通过bootargs传递内核中的模块传递参数

news2025/1/16 13:46:03

前言

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

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

首先能够进入uboot命令行。

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

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

一 编写模块

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

源码gebageba.c

#include <linux/init.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/of.h>

#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_GEBAGEBA
        tristate "this is a module test: parameter send form uboot to this module"
        default M
        help
          This 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, &param, &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 <stdio.h>
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$

小结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/96469.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

模式识别-期末复习题(问题集锦)

1.什么是模式&#xff1f;监督模式识别和非监督模式识别的典型过程分别是什么&#xff1f; 模式&#xff1a;指需要识别且可测量的对象的描述 监督模式识别&#xff1a;分析问题→原始特征提取→特征提取与选择→分类器设计 非监督模式识别&#xff1a;分析问题→原始特征提…

C++ Reference: Standard C++ Library reference: Containers: map: map: insert

C官网参考链接&#xff1a;https://cplusplus.com/reference/map/map/insert/ 公有成员函数 <map> std::map::insert C98 single element (1) pair<iterator,bool> insert (const value_type& val); with hint (2) iterator insert (iterator positio…

【密码学】MD5、UUID,加盐,JWT的理解与使用范例

文章目录MD5加密&#xff1a;1、MD5加密安全访问认证示例代码&#xff1a;2、UUID简介&#xff1a;使用&#xff1a;3、加盐原理&#xff1a;示例代码&#xff1a;4、jwt认知&#xff1a;JWT 结构&#xff1a;范例代码&#xff1a;MD5加密&#xff1a; 1、MD5加密 Message Di…

计算机毕业设计springboot+vue基本微信小程序的疫情防控平台系统

项目介绍 当今社会疫情防控平台是必不可少的,大家都在听从政府的号召在居家隔离,不管是在城市还是在乡镇、农村,这引起我的注目,设计一套社区疫情防控系统,疫情防控需要大家共同努力、团结对社区居民进行了新型冠状病毒肺炎防控知识普及和宣传教育。针对这一需求,本文设计并实现…

LVS详细介绍,这么讲不信你不明白负载均衡

Linux virtual server&#xff0c;是一个基于集群技术和Linux操作系统&#xff0c;目的是实现一个高性能、高可用的服务器&#xff0c;主要工作在网络层。 他采取IP负载均衡&#xff0c;也叫三层负载均衡&#xff08;因为工作在OSI模型的第三层--网络层&#xff09;&#xff0…

java计算机毕业设计springboot+vue旅游攻略平台

项目介绍 目前,我国旅游业正处于高度发展的状态。越来越多的人在假日里选择出游作为放松自己身心的手段。随着网络的普及和发展,人们开始习惯性地在做某事之前先在网络上浏览相关的内容。旅游网站能够帮助游客了解景点相关信息,推出相应的线路信息供游客们选择,并查看相应的旅…

计算机网络实验——路由器的配置静态与RIP配置

前言 由于几个资料和老师给的ppt说的都不清楚&#xff0c;自己也没想到什么很巧妙的归纳方法&#xff0c;写个总结记录一下。 想必静态路由配置的过程中唯一的难点就是ip route这个指令&#xff0c;其他的什么添加接口&#xff0c;设置ip啥的都是基础路由配置中的内容&#xf…

2023春招面试专题:JAVA基础高频面试

ArrayList和LinkedList有哪些区别 ArrayList扩容机制: ArrayList() 会使用长度为零的数组ArrayList(int initialCapacity) 会使用指定容量的数组public ArrayList(Collection<? extends E> c) 会使用 c 的大小作为数组容量add(Object o) 首次扩容为 10&#xff0c;再次…

3D激光里程计其一:ICP

这里写目录标题1. ICP 整体流程2. ICP 的数学表示3. 基于 SVD 的 ICP3.1 旋转部分求解3.2 平移部分求解4. 基于优化的 ICP5. ICP 系列汇总Reference: 深蓝学院-多传感器融合 1. ICP 整体流程 目的&#xff1a;有两个相似的刚体点云&#xff0c;它们之间没有做好配准&#xff…

Golang原理分析:闭包及for range延迟绑定问题原理及解决

1.Golang中的闭包 1.1.什么是闭包 当一个函数引用了环境的变量&#xff0c;被引用的变量与该函数同时存在组成的系统&#xff0c;被称为闭包。 闭包 环境的变量 函数。 以下JavaScript代码展示了一个基础的闭包&#xff1a; name是init函数中的内部变量displayName()是i…

机器学习 鸢尾花(Iris Flower)数据集分析

目录 一&#xff1a;加载数据 二&#xff1a;提取特征数据 三&#xff1a;提取标签数据 四&#xff1a;数据划分 一&#xff1a;加载数据 加载数据&#xff0c;查看数据特征 from sklearn.datasets import load_iris# 1 加载数据 鸢尾花load_iris iris_datasets load_iri…

数据校验及在数据校验的情况下增加headers拿回数据

什么是数据校验&#xff1a; 当你向一个数据端口请求数据时&#xff0c;如果这个数据端口没有设置&#xff1a;Access-Control-Allow-Origin&#xff1a;*&#xff0c;那就是存在跨域限制了&#xff0c;你是拿不回来数据的。图示&#xff1a; 但是有些数据端口是设置了 Access…

【JS ES6】了解学习set类型和weakset类型

✍️ 作者简介: 前端新手学习中。 &#x1f482; 作者主页: 作者主页查看更多前端教学 &#x1f393; 专栏分享&#xff1a;css重难点教学 Node.js教学 从头开始学习 ajax学习 目录set类型与array和object的区别set元素检测与管理类型转换的重要性遍历set类型的方式使用set…

Spring - 事件监听机制 源码解析

文章目录Pre概述ApplicationEvent ------ 事件ApplicationListener ------ 事件监听器ApplicationEventPublisher ------ 事件发布者ApplicationEventMulticaster ------ 事件广播器spring主要的内置事件ContextRefreshedEventContextStartedEventContextStoppedEventContextCl…

设计模式概述之单例模式(四)

很多小伙伴&#xff0c;不知道设计模式是什么&#xff1f; 通常我们所说的设计模式是一种设计方案&#xff0c;是前人留下的经验及最佳实践。 想要学习设计模式&#xff0c;至少要把面向对象的基本结构全部了解。 设计模式&#xff0c;是建立在一定基础上的思维训练。 学习…

喜报 | 中关村发来贺电

2022年12月14日&#xff0c;由中关村金融科技产业发展联盟、中关村互联网金融研究院举办的“中关村金融科技系列活动——2023第十届中关村金融科技论坛年会暨2022“光大杯”中关村番钛客金融科技国际创新大赛颁奖典礼”已圆满落幕。本次会议为建设金融科技中心&#xff0c;共建…

【Pintos】实现自定义 UserProg 系统调用

&#x1f4ad; 写在前面&#xff1a;本文讲解的内容不属于 Pintos 的 Project 项目&#xff0c;而是关于 userprog 如何添加系统调用的&#xff0c;学习如何额外实现一些功能到系统调用中以供用户使用。因为涉及到 src/example 下的Makefile 的修改、lib 目录下 syscall-nr 系统…

搜索二叉树详解

&#x1f9f8;&#x1f9f8;&#x1f9f8;各位大佬大家好&#xff0c;我是猪皮兄弟&#x1f9f8;&#x1f9f8;&#x1f9f8; 文章目录一、搜索二叉树框架二、搜索二叉树概念三、搜索二叉树操作①Erase②Find递归③Insert递归④Erase递归&#xff0c;比Erase更简洁⑤析构函数⑥…

unity学习笔记--day01

今天学习制作了一个简单的抽卡功能&#xff0c;学习结束后目录结构如下&#xff1a; .mate文件是unity生成的配置文件&#xff0c;不用管 制作第一张卡片 创建一个空物体&#xff0c;改名为Card。 在Card下挂载以下UI组件&#xff1a; 编写数据脚本并挂载&#xff0c;unity采用…

Nginx教程(4)—Keepalived

文章目录4.1 高可用集群架构Keepalived双机主备原理4.2 安装Keepalived4.3 Keepalived核心配置文件4.4 Keepalived实现双主机主备高可用测试4.5 高可用集群架构Keepalived双主热备原理Nginx教程一 Nginx教程二 Nginx教程三 4.1 高可用集群架构Keepalived双机主备原理 我们知道…