> For the complete documentation index, see [llms.txt](https://carloss-organization-4.gitbook.io/tech/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://carloss-organization-4.gitbook.io/tech/ecus/imx6-8_documents/imx6-defining-a-u-boot-command.md).

# \[IMX6] Defining A U-Boot Command

## 1. Function Overview

I wish to boot a partition that can be decided in the U-Boot stage. The process is highlighted below:

<figure><img src="/files/jRNMXi8vNDsP9KvPzo95" alt=""><figcaption></figcaption></figure>

I have to compose the U-Boot independent application to implement the logic marked red.&#x20;

## 2. U-Boot independent APP

The U-Boot provides a console we can interact with. This section will introduce how to add an independent command to the U-Boot source code project. In the U-Boot project, each U-Boot provided command is defined by `U_BOOT_CMD` macro in `include/command.h`.

```
#define U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \

cmd_tbl_t __u_boot_cmd_##name Struct_Section = {#name, maxargs, rep, cmd, usage}
```

**Attributes**:

* `name`: The command name;
* `maxargs`: The maximum of the inputted arguments;
* `command`: The C function is mapped to the command;
* `usage`: Usage message;
* ...

### 2.1 Code Base

Assuming the command name is `utils_load`

Add `obj-y += utils_load.o` to `Makefile` in `common` directory.

<figure><img src="/files/QjEKhbVx6ddZ5watV07O" alt=""><figcaption></figcaption></figure>

Create `utils_load.c` file in `common` directory.

<figure><img src="/files/6rA6t4WFcFd7wt3ls4GQ" alt=""><figcaption></figcaption></figure>

The content of `utils_load.c` file is:

```c
#include <common.h>
#include <command.h>
#include <linux/stddef.h>

int do_utils_load(cmd_tbl_t *cmdtp, int flag, int argc, char* const argv[])
{
    int ret = 0;
    int i = 0;

    printf("[INFO] The input is %d\n", argc);
    for (i = 0; i < argc; i ++) {
        printf("[INFO] the argv[%d] is %s\n", i, argv[i]);
    }

finish:
    return ret;
}

U_BOOT_CMD(
    utils_load,
    5,
    1,
    do_utils_load,
    "format : utils_load address",
    "example: utils_load 0x80000000"
);
```

Then build the U-Boot by&#x20;

```shellscript
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
```

in imx6 platform.

### 2.2 Judging Secure Boot

<https://github.com/carloscn/imx-uboot/commit/916419376b988d1a16461810bf358f94ca990e0f#diff-d397fabf5af5abbfeebdcba5c3b68879fb33e5bd432ea70a75e26dbf850a848b>

There are two versions of NXP S32G SoC:

* Rev 1.0
* Rev 2.0 (The HSE is enabled)

The Rev 1.0 hasn't HSE, while the Rev 2.0 has enabled the HSE.

<figure><img src="/files/0Lgrq2CcTDKIWmAN6fIS" alt="" width="375"><figcaption></figcaption></figure>

We can use the version information to distinguish if the SoC has been enabled HSE.

&#x20;

<figure><img src="/files/DTAuPHZaibbiqaAZ7KCl" alt="" width="355"><figcaption><p>without HSE booting log</p></figcaption></figure>

<figure><img src="/files/WmmMTn9feP4yv3uY7Flq" alt="" width="332"><figcaption><p>with HSE booting log</p></figcaption></figure>

The Secure Boot can be distinguished by DDR storage:

<figure><img src="/files/hevCPJDXcoj0WtZtYgNb" alt=""><figcaption></figcaption></figure>

## 3. Examples

Here are some examples of common U-Boot independent applications at <https://cloud.tencent.com/developer/article/1974907>

### 3.1 BEE

```c
#include <common.h>
#include <command.h>
#define GPD0CON		(*(volatile unsigned int *)0x114000A0) //定义蜂鸣器IO口的地址
#define GPD0DAT		(*(volatile unsigned int *)0x114000A4)

int do_beep( cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	GPD0CON&=~(0xf<<0);
	GPD0CON|=(0x1<<0);
	
	if(!strcmp(argv[1],"on"))  //strcmp是比较字符串的函数，如果传进来的是on，就打开蜂鸣器
		{
			GPD0DAT|=(1<<0);	
		}
	if(!strcmp(argv[1],"off"))//strcmp是比较字符串的函数，如果传进来的是off，就关闭蜂鸣器
		{
		 	GPD0DAT&=~(1<<0);	
		}
	else
		printf("Usage:beep <on|off>!\n"); //如果不是on 也不是off  就输出提示
}


U_BOOT_CMD( 
	beep,    //在u-boot命令行里显示的命令名称
	2,       //形参最大个数
	1,       //重复次数 （按下回车--自动执行上一次命令）
	do_beep, //命令执行函数(回调函数--)
	"传参格式: beep <on|off>",   //用法提示
	"传承示例：beep on 或者 beep off......."  //帮助命令的提示信息
);
```

### 3.2 Control LEDs

```c
#include <common.h>
#include <command.h>

/* 1、LED灯接口配置寄存器 */
#define GPM4CON     (*(volatile unsigned int *)0x110002E0)
#define GPM4DAT     (*(volatile unsigned int *)0x110002E4)

int do_led(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	// led 1 on
	// led 1 off
	GPM4CON &= ~(0xf << 0 * 4);    //清除寄存器1
  GPM4CON |=  (1   << 0 * 4);    //输出模式
  
  GPM4CON &= ~(0xf << 1 * 4);    //清除寄存器2
  GPM4CON |=  (1   << 1 * 4);    //输出模式
  
  GPM4CON &= ~(0xf << 2 * 4);    //清除寄存器3
  GPM4CON |=  (1   << 2 * 4);    //输出模式
  
  GPM4CON &= ~(0xf << 3 * 4);    //清除寄存器4
  GPM4CON |=  (1   << 3 * 4);    //输出模式
  
  
  /*第一盏灯*/	
	if(!strcmp(argv[1],"1"))  //strcmp是比较字符串的函数，如果传进来的是on，就打开蜂鸣器
		{
			if(!strcmp(argv[2],"on"))
			{
				GPM4DAT &= ~(1 << 0);      //点亮第一个灯 
			}
			else if(!strcmp(argv[2],"off"))
			{
				GPM4DAT |=1 << 0;          //关闭第一个灯 
			}
		}
		
		/*第二盏灯*/	
	else if(!strcmp(argv[1],"2"))  //strcmp是比较字符串的函数，如果传进来的是on，就打开蜂鸣器
		{
			if(!strcmp(argv[2],"on"))
			{
				GPM4DAT &= ~(1 << 1);      //点亮第二个灯 
			}
			else if(!strcmp(argv[2],"off"))
			{
				GPM4DAT |=1 << 1;          //关闭第二个灯 
			}
		}
	
		/*第三盏灯*/	
	else if(!strcmp(argv[1],"3"))  //strcmp是比较字符串的函数，如果传进来的是on，就打开蜂鸣器
		{
			if(!strcmp(argv[2],"on"))
			{
				GPM4DAT &= ~(1 << 2);      //点亮第三个灯 
			}
			else if(!strcmp(argv[2],"off"))
			{
				GPM4DAT |=1 << 2;          //关闭第三个灯 
			}
		}
		
	/*第四盏灯*/	
	else if(!strcmp(argv[1],"4"))  //strcmp是比较字符串的函数，如果传进来的是on，就打开蜂鸣器
		{
			if(!strcmp(argv[2],"on"))
			{
				GPM4DAT &= ~(1 << 3);      //点亮第四个灯 
			}
			else if(!strcmp(argv[2],"off"))
			{
				GPM4DAT |=1 << 3;          //关闭第四个灯 
			}
		}

	else
		printf("Usage:led <1~4> <on|off>\n"); //如果不是on 也不是off  就输出提示
}


U_BOOT_CMD( 
	led,     //在u-boot命令行里显示的命令名称
	3,       //形参最大个数
	1,       //重复次数
	do_led,  //命令执行函数
	"user: LED count <on|off>",   //用法提示
	"cmd : (1)led  1 on (2)led 1 off...."  //帮助命令的提示信息
);
```

### 3.3 movi

```c
#include <common.h>
#include <command.h>
#include <environment.h>
#include <linux/stddef.h>
#include <malloc.h>
#include <nand.h>
#include <onenand_uboot.h>
#include <mmc.h>
#include <asm/arch/cpu.h>
#include <asm/arch/movi_partition.h>

int do_mymovi(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
	int r_cnt,w_cnt;
   /*1. 查找设备0-SD卡*/
	struct mmc *mmc0 = find_mmc_device(0);
	if(mmc0==NULL)
	{
		printf("设备0查找失败!\n");
		return 0;
	}
	/*2. 查找设备1--MMC*/
	struct mmc *mmc1 = find_mmc_device(1);
	if(mmc1==NULL)
	{
		printf("设备1查找失败!\n");
		return 0;
	}
	/*3. 初始化SD卡*/
    mmc_init(mmc0); /*设备0初始化--SD卡*/
  
  /*4. 初始化EMMC*/
  	mmc_init(mmc1); /*设备1初始化--EMMC卡*/ 
	emmc_boot_open(mmc1); /*设备1打开---EMMC*/
	
	/*5. 烧写数据*/
		/*5.1 BL1*/
		r_cnt=movi_read(0,1,16,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
		w_cnt=movi_write(1,0,16,(void*)0x40008000);//将读出的数据写入到EMMC
		printf("BL1_r_cnt=%d\n",r_cnt);
		printf("BL1_w_cnt=%d\n",w_cnt);
  	
  	/*5.2 BL2*/
  	    r_cnt=movi_read(0,17,32,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
		w_cnt=movi_write(1,16,32,(void*)0x40008000);//将读出的数据写入到EMMC
		printf("BL2_r_cnt=%d\n",r_cnt);
		printf("BL2_w_cnt=%d\n",w_cnt);

	  /*5.3 UBOOT\这里最好使用malloc申请空间，太大的地址可能会被其他数据覆盖掉*/
  		r_cnt=movi_read(0,49,656,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
		w_cnt=movi_write(1,48,656,(void*)0x40008000);//将读出的数据写入到EMMC
		printf("UBOOT_r_cnt=%d\n",r_cnt);
		printf("UBOOT_w_cnt=%d\n",w_cnt);
		
		/*5.4 TZSW*/
  		r_cnt=movi_read(0,705,320,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
		w_cnt=movi_write(1,704,320,(void*)0x40008000);//将读出的数据写入到EMMC
		printf("TZSW_r_cnt=%d\n",r_cnt);
		printf("TZSW_w_cnt=%d\n",w_cnt);
		
		/*5.5 Linux内核*/
  		r_cnt=movi_read(0,1057,12288,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
		w_cnt=movi_write(1,1057,12288,(void*)0x40008000);//将读出的数据写入到EMMC
		printf("Linux内核_r_cnt=%d\n",r_cnt);
		printf("Linux内核_w_cnt=%d\n",w_cnt);
  	emmc_boot_close(mmc1); //关闭EMMC
	
	/*5.5 环境变量*/
	r_cnt=movi_read(0,1025,32,(void*)0x40008000); //读出SD卡里存放到所有数据到DDR指定地址
	w_cnt=movi_write(1,1025,32,(void*)0x40008000);//将读出的数据写入到EMMC
	printf("环境变量_r_cnt=%d\n",r_cnt);
	printf("环境变量_w_cnt=%d\n",w_cnt);
	printf("环境变量拷贝成功!\n");
	return 0;
}

U_BOOT_CMD(
	mymovi,    /*命令的名称*/
	1,          /*形参的最大个数*/
	0,          /*命令执行重复次数*/
	do_mymovi,/*命令处理函数*/
	"将SD卡的BL1/BL2/uboot/签名文件/内核拷贝到EMMC", /*简短提示*/
	"\n"
	"将SD卡的BL1/BL2/uboot/签名文件/内核拷贝到EMMC\n" /*完整提示*/
	"注意: 该命令在开发板以SD卡启动方式时运用\n"
);
```

### 3.4 uboot env copying

```c
#include <common.h>
#include <command.h>
#include <environment.h>
#include <linux/stddef.h>
#include <malloc.h>
#include <nand.h>
#include <onenand_uboot.h>
#include <mmc.h>
#include <asm/arch/cpu.h>
#include <asm/arch/movi_partition.h>

/*
//以MMC方式启动，运行下面命令即可完成环境变量拷贝（SD-->EMMC）
mmc read 1 40000000 401 20
mmc write 0 40000000 401 20

//以SD方式启动，运行下面命令即可完成环境变量拷贝 (SD--->EMMC)
mmc read 0 40000000 401 20
mmc write 1 40000000 401 20
*/
int do_copyenv(cmd_tbl_t * cmdtp, int flag, int argc, char * const argv[])
{
	int r_cnt,w_cnt;
    mmc_init(find_mmc_device(0)); /*设备0初始化--SD卡*/
  	mmc_init(find_mmc_device(1)); /*设备1初始化--EMMC卡*/ 

	/*5.5 环境变量*/
	r_cnt=movi_read(0,1025,32,(void*)0x40000000); //读出SD卡里存放到所有数据到DDR指定地址
	w_cnt=movi_write(1,1025,32,(void*)0x40000000);//将读出的数据写入到EMMC
	printf("环境变量_r_cnt=%d\n",r_cnt);
	printf("环境变量_w_cnt=%d\n",w_cnt);
	printf("环境变量拷贝成功!\n");
	return 0;
}


U_BOOT_CMD(
	copyenv,    /*命令的名称*/
	1,          /*形参的最大个数*/
	0,          /*命令执行重复次数*/
	do_copyenv,/*命令处理函数*/
	"将SD卡的环境变量拷贝到EMMC", /*简短提示*/
	"\n"
	"将SD卡的环境变量拷贝到EMMC\n" /*完整提示*/
	"注意: 该命令在开发板以SD卡启动方式时运用\n"
);
```
