uboot下的开发

目录

SD卡升级

uboot下利用命令行升级的方法

将Uboot版本信息 加入环境变量

fw_printenv

boot的默认CMD参数

自定义组合键进入uboot

uboot增加密码保护

通过uboot cmd进入单用户模式

屏蔽串口打印信息

通过boot cmd参数 禁用console 控制台,关闭串口打印

进一步屏蔽boot的输出信息

通过tftp在uboot 下将RAM上载到tftp服务端


SD卡升级

使用平台 君正,其他平台可能会有一些差异

uboot下利用命令行升级的方法

查看sd卡文件

uboot 中,执行 fatls mmc 0 可以查看 SD 卡中的文件 

加载文件

fatload mmc 0 mem_addr file_name 可以将文件 file_name 传送到 Uboot 的内存

举例):fatload mmc 0 0x80600000 file.bin

擦写(nor flash)
 sf probe;sf erase 0x0 0x1000000;sf write 0x80600000 0x0 0x1000000

在 main_loop 中添加调用

#define JY_SD_UBOOT			"uboot-SN"
#define JY_SD_KERNEL		"kernel-SN"
#define JY_SD_APP			"systrem-SN"


typedef struct SD_bin_head_t
{
	unsigned char jy_flag;
	unsigned char type[32];
	unsigned int crc;
	unsigned int len;
	
	unsigned char tmp[84];//预留84个字节
}SD_bin_head_t;

static int jy_update_crc(const char * name, int crc)
{
	char crc_buf[32];
	sprintf(crc_buf, "%02x",  crc);

	char* cur_crc = getenv(name);
	if (NULL == cur_crc)
	{
		printf("%s is null update UbootVer value %s\n", name, crc_buf);
		setenv(name, crc_buf);
		saveenv();
	}
	else
	{
		if(0 != strcmp(cur_crc, crc_buf))
		{
			printf("update env value [%s]\n", crc_buf);
			setenv(name, crc_buf);
			saveenv();
		}
		else
		{
			return 1;
		}
	}

	return 0;
}

static int CalCrc(int crc, const char *buf, int len)
{
    unsigned int byte;
    unsigned char k;
    unsigned short ACC,TOPBIT;
//    unsigned short remainder = 0x0000;
    unsigned short remainder = crc;
    TOPBIT = 0x8000;
    for (byte = 0; byte < len; ++byte)
    {
        ACC = buf[byte];
        remainder ^= (ACC <<8);
        for (k = 8; k > 0; --k)
        {
            if (remainder & TOPBIT)
            {
                remainder = (remainder << 1) ^0x8005;
            }
            else
            {
                remainder = (remainder << 1);
            }
        }
    }
    remainder=remainder^0x0000;
    return remainder;
}

static int jy_mmc_check()
{
	block_dev_desc_t *stor_dev;
	
	//LOG_INFO("device name %s!\n", "mmc");
	stor_dev = get_dev("mmc", 0);
	if (NULL == stor_dev) {
		printf("error: [jy_mmc_check] Unknow device type!!!\n");
		return -1;
	}
	
	if (fat_register_device(stor_dev, 1) != 0) {
		printf("error: [jy_mmc_check] Unable to use  for fatls!!!\n");
		return -1;
	}

	if (file_fat_detectfs() != 0) {
		printf("error: [jy_mmc_check] file_fat_detectfs failed!!!\n");
		return -1;
	}
	printf("info: [jy_mmc_check] SD find success..\n");
	
	return 0;
}

static int jy_do_upgrade(const char *upg_name, char * const argv[])
{
	u32 offset = 0;
	size_t len = 0;
	
	if (NULL == upg_name)
		return -1;
	
	long sz = file_fat_read(upg_name, 0x80600000, 0x1c00000);
	if (sz < 128)
	{
		printf("info: [jy_do_upgrade] Not find SD bin[%s], sz = %ld.\n", upg_name, sz);
		return -1;
	}
	
	//将升级镜像读入内存
	cmd_tbl_t *bcmd;
	/* Load the rescue image */
	bcmd = find_cmd("fatload");
	if (!bcmd) 
	{
		printf("error: [jy_do_upgrade] find_cmd faild!!!\n");
		return -1;
	}
		
	int ret = do_fat_fsload (bcmd, 0, 5, argv);
	if (0 != ret)
	{
		printf("error: [jy_do_upgrade] do_fat_fsload faild!!!\n");
		return -1;
	}
	
	if (0 == strcmp(upg_name, JY_SD_UBOOT))
	{
		printf("info: [jy_do_upgrade] u-boot partition upgrade start...\n");
		
		len = 256 * 1024;
		offset = 0;

	}
	else if (0 == strcmp(upg_name, JY_SD_KERNEL))
	{
		printf("info: [jy_do_upgrade] kernel partition upgrade start...\n");
		
		len = 3 * 1024 * 1024;	
		offset = 256 * 1024;
	}
	else if (0 == strcmp(upg_name, JY_SD_APP))
	{
		printf("info: [jy_do_upgrade] APP partition upgrade start...\n");
		len = 11010048;
		offset = (3 * 1024 * 1024) + (256 * 1024);
	}
	else
	{
		printf("error: [jy_do_upgrade] Unknow type!!!\n");
		return -1;
	}
		
	//校验升级镜像
	int crc = CalCrc(0, 0x80600000 + sizeof(SD_bin_head_t), len);
	
	SD_bin_head_t *p_head = 0x80600000;
	
	printf("info: [jy_do_upgrade] data[crc = %02x], head[crc = %02x, len = %d] \n", crc, p_head->crc, p_head->len);
	if ((crc != p_head->crc) || (p_head->len != len))
	{
		printf("error: [jy_do_upgrade] Verification failed!!!");
		return -1;
	}
	
	if (jy_update_crc(upg_name, crc))
	{
		printf("info: [jy_do_upgrade] Same version, skip.\n");
		return -1;
	}
	
	struct spi_flash *spi;
	spi = spi_flash_probe(0, 0, 1000000, 0x3);
	if (!spi) {
		printf("%s: spi_flash probe failed.\n", __func__);
		return -1;
	}

	ret = spi_flash_erase(spi, offset, len);
	if (ret) {
		printf("%s: spi_flash erase failed.\n", __func__);
		return -1;
	}

	ret = spi_flash_write(spi, offset, len, 0x80600000 + sizeof(SD_bin_head_t));
	if (ret) {
		printf("%s: spi_flash write failed.\n", __func__);
		spi_flash_free(spi);
		return -1;
	}
	spi_flash_free(spi);
	
	printf("info: [jy_do_upgrade] SD upg success..\n");
	
	return 0;
}

static void jy_mmc_upg()
{
	int ret = 0;
	int old_ctrlc;
	
	printf("info: [jy_mmc_upg] check..\n");
	
	//检查是否插入了fat32格式的SD卡
	if (0 != jy_mmc_check())
		return;
	
	old_ctrlc = disable_ctrlc(0);
	
	char * const boot_argv[5] = { "fatload", "mmc", "0", "0x80600000", JY_SD_UBOOT};
	ret = jy_do_upgrade(JY_SD_UBOOT, boot_argv);
	if (0 == ret)
		saveenv();
	
	char * const kernel_argv[5] = { "fatload", "mmc", "0", "0x80600000", JY_SD_KERNEL};
	ret = jy_do_upgrade(JY_SD_KERNEL, kernel_argv);	
	
	char * const app_argv[5] = { "fatload", "mmc", "0", "0x80600000", JY_SD_APP};
	ret = jy_do_upgrade(JY_SD_APP, app_argv);	
	
	disable_ctrlc(old_ctrlc);
}

注:SD卡升级接口最好放在 读秒之前,main.c中的main_loop中。

将Uboot版本信息 加入环境变量

需要包含头文件#include <version.h>

	char szUbootVer[68];
	snprintf(szUbootVer, 64, "12XP %s", version_string);
	char* UbootVer = getenv("UbootVer");
	if (NULL == UbootVer)
	{
		printf("UbootVer is null update UbootVer value 0000\n");
		setenv("UbootVer", (char*)szUbootVer);
		saveenv();
	}
	else
	{
		if(strcmp(UbootVer, (char*)szUbootVer) !=0)
		{
			printf("update UbootVer value \n");
			setenv("UbootVer", (char*)szUbootVer);
			saveenv();
		}
	}

上层解析版本并转成16进制

static int parse_uboot_version(char * p_uboot_ver, char *p_ver)
{		
    if (NULL == p_uboot_ver || NULL == p_ver)
    {
        printf("p_uboot_ver=%p p_jy_ver=%p param error!\n", p_uboot_ver, p_ver);
        return -1;
    }

    char ver_tmp[64] = { 0 };
	char chip_tmp[64] = { 0 };
	sscanf(p_uboot_ver, "%*[^(](%[^)]64s", ver_tmp);
	sscanf(p_uboot_ver, "%*[^=]=%[^ ]64s", chip_tmp);

    char mon[3] = {0};	    
    sys_version_info_t ver_info;
    memset(&ver_info, 0, sizeof(ver_info)); 
    
	sscanf(ver_tmp, "%3s %2d %4d - %2d:%2d:%2d", mon, &ver_info.date, &ver_info.year,
		&ver_info.hour, &ver_info.min, &ver_info.sec);
    
    convert_2_inte_month(mon, &ver_info.mon);

	sprintf(p_ver, "%s%02X%02X%02X%02X%02X%02X\n", chip_tmp, ver_info.year%100, ver_info.mon, ver_info.date,
		ver_info.hour, ver_info.min, ver_info.sec);		

	return 0;
}

重新编译后进入uboot查看

fw_printenv

linux下查看环境变量可以使用fw_printenv

在uboot代码目录下make HOSTCC=mips-linux-uclibc-gnu-gcc env,编译后有报错不影响,将tools/env/下生成的fw_printenv和fw_env.config拷贝到目标机即可

这里fw_env.config的参数

Device offset 对应  CONFIG_ENV_OFFSET

Env. size 对应 CONFIG_ENV_SIZE

Flash sector size 对应 CONFIG_ENV_SECT_SIZE

 

(以上情况对应的是ENV分区和boot在一个分区的情况,所以这里的Device offset 就是要偏移到ENV信息的位置)

如果是ENV时单独的一个分区,比如:

这里Device offset就是0x0 从开头开始。

Env大小是256KB,所以Env. size就是0x40000

Flash sector是一个block的大小,这款flash是128KB所以是0x20000,总大小256KB,所以有两个block, Flash sector size 为2

boot的默认CMD参数

boot下printenv可以看到环境变量,环境变量可以通过setenv写入其对应的分区位置。

如果环境变量中没有写入内容 则会使用boot中的默认参数。

找到平台对应的头文件修改或者增加即可boot\include\configs\infinity6b0.h(mstar),注意不同平台版本对应宏定义名称可能不同。

自定义组合键进入uboot

正常情况下 我们进入uboot的方式是在读秒的时候按回车, 但是如果可以修改进入的方式,这样别人就算拿到我们的设备也没办法轻易进入uboot。

修改内容:

修改文件:uboot\common\main.c

abortboot_normal修改的方法:

 加密原理:在uboot倒计时阶段  自定义组合键方式  进入uboot,我这里用的是0x1f 即【<ctrl> + <shift> + <->】的组合键才能进入uboot

如果是在abortboot_keyed中修改:

可以直接赋值

也可以找到对应的宏定义在头文件中修改

  获取组合键的ascii方法:

#include <stdio.h>
 
int main(void)
{
		int in;
 
		in = getchar();
		printf("%#x\n", in);
 
		return 0;
}

uboot增加密码保护

mstar平台

默认uboot 按回车即可进入控制台,安全一点的做法可以 自定义组合键进入 boot ,更安全的做法,进入boot 之后可以加一层密码保护效果如下

输入正确的密码之后才能 成功登陆。

void main_loop(void)增加 我们的login_autch接口

这里用到了aes对输入的密码进行加密后比较也可以直接明文比较

修改lib/Makefile 增加对aes.c的编译(这里不同的平台打开使用aes的方式不同,有些平台可以通过menuconfig 打开,我这里没有menuconfig配置开关,因此自己修改)

找到Makefile修改的过程:

1、在boot代码里面搜索发现有aes的实现aes.c,于是直接引用,发现编译报错未定义,于是找到aes.c所在路径boot/lib/发现没有生成.o。

2、在aes.c所在路径下随便找一个 有生成.o(这里找的是errno.o)的文件,进到Makefile中找到对应的位置仿照添加 aes.o 如下图:

 login_autch实现

#include <aes.h>

#define CONFIG_JY_LOGIN_PWD				"f7423c53cf548719b5c610d"


static int do_aes_cbc_encrypt(unsigned char *data, int len)
{
	u8 key[AES_KEY_LENGTH] = { 0x0c, 0x46, 0x31, 0x3a, 0xee, 0xf6, 0xff, 0x73, 0xd8, 0xdd, 0x8e, 0xee, 0x36, 0x1c, 0x6a, 0x7b };
	u8 iv[AES_KEY_LENGTH] = { 0 };
	u8 key_exp[AES_EXPAND_KEY_LENGTH];
	u32 num_aes_blocks = 0;

	num_aes_blocks = (len + AES_KEY_LENGTH - 1) / AES_KEY_LENGTH;
	aes_expand_key(key, key_exp);
	aes_cbc_encrypt_blocks(key_exp, (u8*)data, (u8*)data, num_aes_blocks);

	return 0;
}

static void login_auth(void)
{
#define MAX_PASSWD_LEN	16
#define PASSWD_STR		"password: "

	int auth = 0;
	char in_pass[MAX_PASSWD_LEN * 2];
	char enc_pass[MAX_PASSWD_LEN * 2] = {0xd9, 0x0, 0xca, 0xff, 0x37, 0xaf, 0xee, 0xd, 0xbf, 0x73, 0xc4, 0x91, 0xb9, 0x7, 0x50, 0xf};
	

	int len = 0, enc_len;
	int c, i;

	while (!auth) {
		puts(PASSWD_STR);

		memset(in_pass, 0, MAX_PASSWD_LEN * 2);
		
		len = 0;
		while (1) {
			if (tstc()) {
				/* Check for input string overflow */
				if (len >= MAX_PASSWD_LEN)
					break;

				c = getc();

				if ('\r' == c || '\n' == c)
					break;
				else if ('\0' == c || 0x1f == c)
					continue;

				in_pass[len++] = c;
			}
		}

		if (len > 0) {

			do_aes_cbc_encrypt((u8*)in_pass, len);





			printf("do_aes_cbc_encrypt	in_pass \n");

			for (i = 0; i < MAX_PASSWD_LEN; ++i)
				printf("%#x ", in_pass[i]);
			printf("\n\n");

			printf("do_aes_cbc_encrypt	enc_pass \n");

			for (i = 0; i < MAX_PASSWD_LEN; ++i)
				printf("%#x ", enc_pass[i]);
			printf("\n\n");

			//printf("shj debug boot passwd --- ##len = %d [%s][%s] \n", len, in_pass, enc_pass);







			auth = 1;
			for (i = 0; i < MAX_PASSWD_LEN; i++) {
				if (in_pass[i] ^ enc_pass[i]) {
					auth = 0;
					printf("AES  faild\n");
					break;
				}
			}

			

			if (!strcmp(in_pass, enc_pass))
			{		
				printf("success\n");
				auth = 1;
			}
			else
			{
				//auth = 1;/
				printf("faild\n");
			}

	
	
		}

		puts("\r\n");
	}
}

通过uboot cmd进入单用户模式

在ARM中,bootargs参数用于传递引导参数给内核。在某些Linux发行版中,bootargs参数可以设置为"single"。"single"参数的作用是将系统引导到单用户模式,这通常用于系统维护和修复。

在单用户模式下,只有root用户可以访问系统,其他用户无法登录。这使得系统管理员可以更安全地进行系统维护和故障排除,而不会受到其他用户的干扰。另外,单用户模式还提供了root权限,允许系统管理员执行一些敏感操作,例如修改系统文件、调整系统设置等。

需要注意的是,不同的Linux发行版可能对bootargs参数的设置有所不同。因此,具体的操作步骤和效果可能因发行版而异。

屏蔽串口打印信息

通过boot cmd参数 禁用console 控制台,关闭串口打印

出于安全考虑,需要关闭串口打印内容,防止信息被窃取。可以通过在bootargs后面增添console=null来实现

修改后将不会输出内核已经程序打印,但是后台依然是正常可用的

在arm linux系统中传递kernel参数:禁用console(控制台)/取消命令行界面/取消串口打印_linux 禁用 console-CSDN博客

进一步屏蔽boot的输出信息

修改代码(Mstar)

效果:

通过tftp在uboot 下将RAM上载到tftp服务端

以nand为例子

补齐ip mask getway等项

拿到分区地址信息 比如:0x000000400000-0x000000800000 : "rootfs"

nand read、tftpput

拆解镜像 unsquashfs

我这里是squashfs文件系统

./unsquashfs -d out_rootfs rootfs.bin

重新压缩镜像 mksquashfs

mksquashfs_4.2 out_rootfs/ rootfs-new1.bin

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值