开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第19天,点击查看活动详情
一、命令体系基础知识
- 每一个uboot的命令对应一个函数do_命令名字,例如do_bootm
- 命令是可以传参的,参数以argc&argv传给函数
例如:int do_bootm(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[]); - uboot的命令体系在工作时,一个命令对应一个cmd_tbl结构体的一个实例,然后uboot支持多少个命令,就需要多少个结构体实例。uboot的命令体系把这些结构体实例管理起来,当用户输入了一个命令时,uboot会去这些结构体实例中查找(查找方法和存储管理的方法有关)。如果找到则执行命令,如果未找到则提示命令未知。
1.1、命令结构体
-
命令结构体cmd_tbl
struct cmd_tbl { char *name; /* Command Name */ int maxargs; /* maximum number of arguments */ /* * Same as ->cmd() except the command * tells us if it can be repeated. * Replaces the old ->repeatable field * which was not able to make * repeatable property different for * the main command and sub-commands. */ int (*cmd_rep)(struct cmd_tbl *cmd, int flags, int argc, char *const argv[], int *repeatable); /* Implementation function */ int (*cmd)(struct cmd_tbl *cmd, int flags, int argc, char *const argv[]); char *usage; /* Usage message (short) */ #ifdef CONFIG_SYS_LONGHELP char *help; /* Help message (long) */ #endif #ifdef CONFIG_AUTO_COMPLETE /* do auto completion on the arguments */ int (*complete)(int argc, char *const argv[], char last_char, int maxv, char *cmdv[]); #endif }; -
name:命令名称,字符串格式
-
maxargs:命令最多可以接收多少个参数
-
cmd_rep:指示这个命令是否可重复执行
-
cmd:函数指针,命令对应的函数的函数指针
-
usage:命令的短帮助信息
-
help:命令的长帮助信息
-
complete:函数指针,指向这个命令的自动补全的函数
1.2、命令的管理方式
管理方式:数组,链表等
uboot管理方式是:通过自定义段,实现
-
给命令结构体实例附加特定段属性(用户自定义段),链接时将带有该段属性的内容链接在一起排列(挨着的,不会夹杂其他东西,也不会丢掉一个带有这种段属性的,但是顺序是乱序的)。
-
uboot重定位时将该段整体加载到DDR中。加载到DDR中的uboot镜像中带有特定段属性的这一段其实就是命令结构体的集合,有点像一个命令结构体数组。
-
段起始地址和结束地址(链接地址、定义在u-boot.lds中)决定了这些命令集的开始和结束地址。
-
U_BOOT_CMD宏:位置common/command.h
二、uboot命令体系执行
- cli_loop函数,就是一个获取命令、解析命令、执行命令的过程参考博文
位置:common/cli.c - cmd_process函数,就是查找执行处理命令的函数
位置:common/command.c - find_cmd查找命令,位置common/command.c
- cmd_call:执行命令
三、添加命令
-
在u-boot-2022.01/cmd下,新建文件xw.c
可以cp里面的echo.c文件 -
在common/cmd/Makefile中添加上xw.o,目的是让Make在编译时编译链接进去
-
xw.c
#include <common.h> 8 #include <command.h> 9 10 static int do_xw(struct cmd_tbl *cmdtp, int flag, int argc, 11 char *const argv[]) 12 { 13 if (argc > 1) { 14 printf("argc>1\n"); 15 }else{ 16 printf("xw do_xw zhixing\n"); 17 } 18 19 return 0; 20 } 21 22 U_BOOT_CMD( 23 xw, 1, 1, do_xw, 24 "Custom Commands xw", 25 "Custom Commands xw!!!" 26 );
四、环境变量
- 环境变量的作用
可以不需要修改源码,修改运行时需要的一些数据和特性 - 环境变量优先级
uboot和环境变量中各有一个值,如果环境变量为空则适用代码的值,否则则使用环境变量的值
4.1、环境变量的工作方式
- 刚烧录的系统中环境变量分区是空白的,uboot第一次运行时加载的是uboot代码中自带的一份环境变量,叫默认环境变量
- saveenv时DDR中的环境变量会被更新到SD卡的环境变量中,下次开机就会在SD卡中加载环境变量到DDR中
4.2、默认环境变量
- 位置u-boot-2022.01/include/env_default.h
default_environment
是一个字符数组,大小为ENV_SIZE,内容就是很多个环境变量连续分布组成,每个环境变量最末端以'\0'结束 - ENV_SIZE环境变量最大内存,10k
五、printenv命令
位置:u-boot-2022.01\cmd\nvedit.c
- 可以看出printenv命令对应的函数是do_env_print
- 首先判断输入命令是否是加了-a的,如果没有加,就argc=1进入env_print函数循环打印所有的环境变量出来
六、驱动认识
- 裸机程序中是直接操控硬件的,操作系统中必须通过驱动来操控硬件。这两个的本质区别就是分层
- linux驱动本身做了模块化设计,linux驱动本身和linux内核不是强耦合的
- 驱动的设计中有一个关键数据结构(结构体),结构体中包含一些变量和一些函数指针
变量用来记录驱动相关的一些属性,函数指针用来记录驱动相关的操作方法
这些变量和函数指针加起来就构成了驱动。驱动就被抽象为这个结构体 - 一个驱动工作时主要就分几部分:驱动构建(构建一个struct mmc然后填充它)
驱动运行时(调用这些函数指针指针的函数和变量) - 分离思想
分离思想就是说在驱动中将操作方法和数据分开
操作方法就是函数,数据就是变量
在不同的地方来存储和管理驱动的操作方法和变量,这样的优势就是驱动便于移植。 - 分层思想
分层思想是指一个整个的驱动分为好多个层次
简单理解就是驱动分为很多个源文件,放在很多个文件夹中