RK356x U-Boot研究所(命令篇)3.1 U-Boot命令的定义(以demo命令为例)

本文深入探讨了U-Boot中的demo命令,从命令定义、cmd_tbl_t数据结构到do_demo函数的实现。通过分析源代码,解释了命令如何通过宏定义和数据结构在U-Boot中工作,揭示了命令参数检查、回调函数查找及设备驱动交互的过程,展示了U-Boot命令执行的内部机制。
平台U-Boot 版本Linux SDK 版本
RK356x2017.09v1.2.3

U-Boot 中自带一个 demo 命令,这个命令定义在cmd/demo.c文件,透过它,可以很容易理解 U-Boot 命令是如何定义以及如何使用!

一、demo命令的定义

打开cmd/demo.c文件,直接拖到最底下就能看到demo命令的定义:

可以看到demo命令直接引用U_BOOT_CMD宏函数定义,这个宏函数定义在include/command.h头文件:


从宏函数定义的参数,可以知道 demo命令的定义参数意义如下:

形参实参意义
_namedemo名字
_maxargs4最大参数个数
_rep1允许自动重复?(输入该命令并执行后,再次回车可重复执行,参数为0或1)
_cmddo_demo回调函数
_usage“Driver model (dm) demo operations”描述
_help“list                                        List available demo devices\n”
“demo hello <num> [<char>]       Say hello\n”
“demo light [<num>]                    Set or get the lights\n”
“demo status <num>                   Get demo device status\n”
“demo list                                    List available demo devices”
使用说明

U_BOOT_CMD继续调用U_BOOT_CMD_COMPLETE宏函数,来看看U_BOOT_CMD_COMPLETE的定义:

这里的COMPLETE应该翻译成填充,而不是完成!

U_BOOT_CMD_COMPLETE相比U_BOOT_CMD宏函数,只是传多一个_comp参数,这个参数的实参是NULL,这里可以看出U_BOOT_CMD其实是U_BOOT_CMD_COMPLETE的简化版。

U_BOOT_CMD_COMPLETE使用两个宏去定义变量并初始化:


这个ll_entry_declare宏函数定义在include/linker_lists.h头文件,这个函数的作用是Declare linker-generated array entry,翻译过来就是声明链接器生成的数组条目!

U_BOOT_CMD_MKENT_COMPLETE宏函数的定义如下:


_CMD_HELP_CMD_COMPLETE宏函数的定义如下:


由于宏是预处理阶段会进行展开替换,因此demo的实际展开过程如下:

U_BOOT_CMD(
	demo,   4,      1,      do_demo,
	"Driver model (dm) demo operations",
	"list                     List available demo devices\n"
	"demo hello <num> [<char>]     Say hello\n"
	"demo light [<num>]            Set or get the lights\n"
	"demo status <num>             Get demo device status\n"
	"demo list                     List available demo devices"
);

U_BOOT_CMD展开后:

U_BOOT_CMD_COMPLETE(
	demo,   4,      1,      do_demo,
	"Driver model (dm) demo operations",
	"list                     List available demo devices\n"
	"demo hello <num> [<char>]     Say hello\n"
	"demo light [<num>]            Set or get the lights\n"
	"demo status <num>             Get demo device status\n"
	"demo list                     List available demo devices",
	NULL
);

U_BOOT_CMD_COMPLETE展开后:

ll_entry_declare(cmd_tbl_t, demo, cmd) =			\
	U_BOOT_CMD_MKENT_COMPLETE(demo, 4, 1, do_demo,	\
					"Driver model (dm) demo operations",	\
					"demo hello <num> [<char>]     Say hello\n"	\
					"demo light [<num>]            Set or get the lights\n"	\
					"demo status <num>             Get demo device status\n"	\
					"demo list                     List available demo devices",	\
					NULL);

ll_entry_declareU_BOOT_CMD_MKENT_COMPLETE_CMD_HELP_CMD_COMPLETE展开后:

cmd_tbl_t _u_boot_list_2_cmd_2_demo __aligned(4)		\
		__attribute__((unused,				\
		section(".u_boot_list_2_cmd_2_demo))) =			\
			{	\
					"demo", 4, 1, do_demo, "Driver model (dm) demo operations",			\
					"Driver model (dm) demo operations",	\
					"demo hello <num> [<char>]     Say hello\n"	\
					"demo light [<num>]            Set or get the lights\n"	\
					"demo status <num>             Get demo device status\n"	\
					"demo list                     List available demo devices",	\
					NULL,	\
			};

二、cmd_tbl_t的数据结构

cmd_tbl_t的数据结构定义在include/command.h头文件:

cmd_tbl_t其实是struct cmd_tbl_s,数据结构的意义与前面分析的一致!complete函数指针传进入的是NULL,这个不用理会!

三、do_demo函数的定义

do_demo函数的定义如下:

除了函数名可以自定义,其他都是固定写法,参考cmd_tbl_tcmd函数指针定义,函数名一般是do_<cmd>这样的形式命名!

do_demo的函数体如下:


首先是判断argc是否小于2,这里其实是判断命令参数的个数,要求至少2个参数以上(包括2个),若失败则直接返回CMD_RET_USAGE宏,该宏调用cmd_usage()函数,它在功能上会打印出前面定义的帮助信息:


当然,这样类似的宏定义共有三个(其余两个是成功与失败):


接着往下走,调用find_cmd_tbl函数:


这个函数的声明如下:

从参数不难理解,应该是通过命令行字符串获取对应的cmd的处理函数,来看看demo_commands是如何定义的:


看来是通过argv[1]参数找到对应的回调函数进行返回,例如argv[1]的字符串是list,那么就返回do_demo_list

来看看U_BOOT_CMD_MKENT宏函数的定义:


再看看U_BOOT_CMD_MKENT_COMPLETE宏函数的定义:


这个宏函数的作用与之前U_BOOT_CMD_COMPLETE有点不一样(缺少ll_entry_declare对变量的定义):


因此在此处是单纯的全局变量定义(定义一个cmd_tbl_t 类型的数组),并把作用域限制在当前文件:

static cmd_tbl_t demo_commands[] = {
	{ "list", 0, 1, do_demo_list, "", "", NULL },
	{ "hello", 2, 1, do_demo_hello, "", "", NULL },	
	{ "light", 2, 1, do_demo_light, "", "", NULL },	
	{ "status", 1, 1, do_demo_status, "", "", NULL },	
};

接下来是判断错误逻辑:


传递的参数不对之时就会返回命令使用说明。

然后通过argc的个数为0,则认为传入的命令为demo list,否则认为是其余命令:


其中simple_strtoul(argv[0], NULL, 10)的作用是把字符串转化为10进制数;uclass_get_device(UCLASS_DEMO, devnum, &demo_dev)通过UCLASS_DEMO宏以及设备号获取demo设备,这属于U-Boot DM(Driver Model);cmd_process_error的声明如下:


这个cmd_process_error用于报告命令执行情况,返回数是以下三者之一:

最后是执行命令的回调函数:


以下是各个回调函数的定义:

  • demo list的回调函数:

  • demo hello <num> [<char>]的回调函数:

  • demo status <num>的回调函数:

  • demo light [<num>]的回调函数:


从这些回调函数中不难发现,函数最终是要调用到底层设备驱动中去,底层部分提供API给命令进行调用,体现了分层的概念!

课程简述  Android是目前最为流行的移动操作系统之一,它的开发涉及到多个知识领域。本课程将深入介绍Android系统启动过程中的重要组成部分——init进程,并探讨与之相关的多项关键技术。我们还将提供实际的开发案,以RK3399开发板为,通过演示Android产品配置、init启动流程、selinux权限管理、init.rc启动脚本定制等实际案,让学员深入理解这些技术在实际产品开发中的应用场景和实现方法,提高学员的实际开发能力和经验,从而更好地应对实际产品开发中遇到的问题和挑战。知识运用方向学习Android启动方面的知识,可以参与如下实际开发工作项:启动流程定制: 根据产品需求调整Android启动流程,包括修改init.rc脚本、修改启动顺序和等待时间、加入自定义服务等。属性系统定制: 通过Android属性系统定制化启动流程,如增加产品版本信息、定制开机音量等。日志系统分析: 掌握日志的捕捉、分析和排错技术,在启动过程中,需要加入调试信息来方便开发人员进行调试,同时需要进行日志的优化,避免日志输出过多占用过多的系统资源。selinux安全策略定制:在Android系统中,selinux是一种安全机制,用于保护系统的敏感资源和数据。在实际开发中,可能需要对selinux策略进行定制,以确保系统的安全性和稳定性。课程内容主要内容简述1RK3399 开发板操作这部分内容重点介绍如何在FIreFly开发板上将Android 10系统运行起来, 包含编译FireFly的Android源码下载和编译, 镜像烧录运行,内核和模块编译,以及RK3399内核启动init进程的过程。2, 产品定制这部分讲解获取到方案商或者原厂提供的源码后, 如何定制一个新的产品,产品配置文件和模型, 原始代码中的配置文件和定制化东西3, Android日志代码编写之前讲过Android的日志系统, 并没涉及到代码编写, 这个部分重点讲解C/C++, java代码编写日志的API和代码4, 属性系统在Android中,属性使用的非常频繁的,可以用来作为进程间通信,也可以用于一些行为控制, 这个部分会重点介绍属性系统框架, API接口, 属性文件等知识点5,selinux进程对文件进行访问时,Android 4.3就开始集成了selinux权限管控, 如果需要启动某个脚本或者服务, selinux的配置就避免不了,并且Android8之后, Android系统对进程访问的权限管控的非常严格。6, init.rc脚本Android定义的一种脚本, 改脚本是有init进程启动, 是非常重要的一个脚本, 会包含系统中的其他很多脚本, 在我们系统开发时, 我们经常通过这个脚本进行一些定制化动作。7, init进程代码分析想要了解一个系统,就必须对源码进行分析和理解, 这个章节,带大家去跟读init进程代码, 这样,换了另外一个Android版本,完全就可以去读代码, 知道有什么变化。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式逍遥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值