uboot命令体系及硬件驱动

97 阅读5分钟

​开启掘金成长之旅!这是我参与「掘金日新计划 · 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、环境变量的工作方式

  1. 刚烧录的系统中环境变量分区是空白的,uboot第一次运行时加载的是uboot代码中自带的一份环境变量,叫默认环境变量
  2. 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然后填充它)
    驱动运行时(调用这些函数指针指针的函数和变量)
  • 分离思想
    分离思想就是说在驱动中将操作方法和数据分开
    操作方法就是函数,数据就是变量
    在不同的地方来存储和管理驱动的操作方法和变量,这样的优势就是驱动便于移植。
  • 分层思想
    分层思想是指一个整个的驱动分为好多个层次
    简单理解就是驱动分为很多个源文件,放在很多个文件夹中