香橙派orangepi pc plus h3 uboot保存环境变量失败解决——Unable to use mmc 1:1... Failed (1)

前言

环境介绍:

1.编译环境

Ubuntu 18.04.5 LTS

2.SDK

orangepi Linux 5.4 SDK

3.uboot

v2020.04

一、现象

根据《OrangePi_PCPlus_H3_用户手册_v3.1.pdf》5. Linux 5.4 SDK使用说明编译好镜像文件,将Linux 镜像烧写到 tf卡,启动板卡 ,uboot按空格键停留再uboot,保存环境变量,打印如下:

U-Boot 2020.04-orangepi (Jan 02 2021 - 19:58:40 +0800) Allwinner Technology

CPU:   Allwinner H3 (SUN8I 1680)
Model: Xunlong Orange Pi PC Plus
DRAM:  1 GiB
MMC:   Device 'mmc@1c11000': seq 1 is in use by 'mmc@1c10000'
mmc@1c0f000: 0, mmc@1c10000: 2, mmc@1c11000: 1
Loading Environment from FAT... Unable to use mmc 1:1... In:    serial
Out:   serial
Err:   serial
Net:   phy interface0
eth0: ethernet@1c30000
230456 bytes read in 14 ms (15.7 MiB/s)
starting USB...
Bus usb@1c1a000: USB EHCI 1.00
Bus usb@1c1a400: USB OHCI 1.0
Bus usb@1c1b000: USB EHCI 1.00
Bus usb@1c1b400: USB OHCI 1.0
Bus usb@1c1c000: USB EHCI 1.00
Bus usb@1c1c400: USB OHCI 1.0
Bus usb@1c1d000: USB EHCI 1.00
Bus usb@1c1d400: USB OHCI 1.0
scanning bus usb@1c1a000 for devices... 1 USB Device(s) found
scanning bus usb@1c1a400 for devices... 1 USB Device(s) found
scanning bus usb@1c1b000 for devices... 1 USB Device(s) found
scanning bus usb@1c1b400 for devices... 1 USB Device(s) found
scanning bus usb@1c1c000 for devices... 1 USB Device(s) found
scanning bus usb@1c1c400 for devices... 1 USB Device(s) found
scanning bus usb@1c1d000 for devices... 1 USB Device(s) found
scanning bus usb@1c1d400 for devices... 1 USB Device(s) found
       scanning usb for storage devices... 0 Storage Device(s) found
Autoboot in 1 seconds, press <Space> to stop
=>
=> saveenv
Saving Environment to FAT... Unable to use mmc 1:1... Failed (1)

无法保存环境变量,并且在前面加载环境变量的时候也出现了同样的打印信息,无法使用mmc 1:1

Unable to use mmc 1:1... Failed (1)

二、问题定位

直接在uboot搜索“Unable to use”
在这里插入图片描述
检索发现打印信息出自
env/fat.c
总共有两个函数有该打印信息

2.1 env_fat_load(void)

static int env_fat_load(void)
{
	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
	struct blk_desc *dev_desc = NULL;
	disk_partition_t info;
	int dev, part;
	int err;

#ifdef CONFIG_MMC
	if (!strcmp(CONFIG_ENV_FAT_INTERFACE, "mmc"))
		mmc_initialize(NULL);
#endif

	part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,
					CONFIG_ENV_FAT_DEVICE_AND_PART,
					&dev_desc, &info, 1);
	if (part < 0)
		goto err_env_relocate;

	dev = dev_desc->devnum;
	if (fat_set_blk_dev(dev_desc, &info) != 0) {
		/*
		 * This printf is embedded in the messages from env_save that
		 * will calling it. The missing \n is intentional.
		 */
		printf("Unable to use %s %d:%d... ",
		       CONFIG_ENV_FAT_INTERFACE, dev, part);
		goto err_env_relocate;
	}

	err = file_fat_read(CONFIG_ENV_FAT_FILE, buf, CONFIG_ENV_SIZE);
	if (err == -1) {
		/*
		 * This printf is embedded in the messages from env_save that
		 * will calling it. The missing \n is intentional.
		 */
		printf("Unable to read \"%s\" from %s%d:%d... ",
			CONFIG_ENV_FAT_FILE, CONFIG_ENV_FAT_INTERFACE, dev, part);
		goto err_env_relocate;
	}

	return env_import(buf, 1);

err_env_relocate:
	env_set_default(NULL, 0);

	return -EIO;
}

2.2 env_fat_save(void)

static int env_fat_save(void)
{
	env_t __aligned(ARCH_DMA_MINALIGN) env_new;
	struct blk_desc *dev_desc = NULL;
	disk_partition_t info;
	int dev, part;
	int err;
	loff_t size;

	err = env_export(&env_new);
	if (err)
		return err;

	part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,
					CONFIG_ENV_FAT_DEVICE_AND_PART,
					&dev_desc, &info, 1);
	if (part < 0)
		return 1;

	dev = dev_desc->devnum;
	if (fat_set_blk_dev(dev_desc, &info) != 0) {
		/*
		 * This printf is embedded in the messages from env_save that
		 * will calling it. The missing \n is intentional.
		 */
		printf("Unable to use %s %d:%d... ",
		       CONFIG_ENV_FAT_INTERFACE, dev, part);
		return 1;
	}

	err = file_fat_write(CONFIG_ENV_FAT_FILE, (void *)&env_new, 0, sizeof(env_t),
			     &size);
	if (err == -1) {
		/*
		 * This printf is embedded in the messages from env_save that
		 * will calling it. The missing \n is intentional.
		 */
		printf("Unable to write \"%s\" from %s%d:%d... ",
			CONFIG_ENV_FAT_FILE, CONFIG_ENV_FAT_INTERFACE, dev, part);
		return 1;
	}

	return 0;
}

从函数名判断
env_fat_save是保存环境变量时调用
env_fat_load是uboot一开始加载环境变量时调用
但都集中与下面这函数

if (fat_set_blk_dev(dev_desc, &info) != 0) {
	/*
	 * This printf is embedded in the messages from env_save that
	 * will calling it. The missing \n is intentional.
	 */
	printf("Unable to use %s %d:%d... ",
	       CONFIG_ENV_FAT_INTERFACE, dev, part);
	return 1;
}

其中fat_set_blk_dev定义在
fs/fat/fat.c

int fat_set_blk_dev(struct blk_desc *dev_desc, disk_partition_t *info)
{
	ALLOC_CACHE_ALIGN_BUFFER(unsigned char, buffer, dev_desc->blksz);

	cur_dev = dev_desc;
	cur_part_info = *info;

	/* Make sure it has a valid FAT header */
	if (disk_read(0, 1, buffer) != 1) {
		cur_dev = NULL;
		return -1;
	}

	/* Check if it's actually a DOS volume */
	if (memcmp(buffer + DOS_BOOT_MAGIC_OFFSET, "\x55\xAA", 2)) {
		cur_dev = NULL;
		return -1;
	}

	/* Check for FAT12/FAT16/FAT32 filesystem */
	if (!memcmp(buffer + DOS_FS_TYPE_OFFSET, "FAT", 3))
		return 0;
	if (!memcmp(buffer + DOS_FS32_TYPE_OFFSET, "FAT32", 5))
		return 0;

	cur_dev = NULL;
	return -1;
}

2.3 疑点1

该函数作用是检查tf卡分区以及文件类型的,ps具体不是很懂哈~
从打印情况来看,估计采用推荐的格式化工具格式化tf卡出了问题。

2.4 疑点2

uboot打印的"mmc 1:1…"到底啥意思?
打印的源码如下:

printf("Unable to use %s %d:%d... ",
       CONFIG_ENV_FAT_INTERFACE, dev, part);

CONFIG_ENV_FAT_INTERFACE 为mmc 定义如下,可以理解为环境变量的接口,也就是环境变量的存储介质。

include/generated/autoconf.h
#define CONFIG_ENV_FAT_INTERFACE "mmc"

dev则为h3 mmc的设备号。
h3总共有三个mmc接口,如下是《Allwinner_H3_Datasheet_v1.2.pdf》找到的。
在这里插入图片描述
与uboot一开始打印的信息可以对应上

mmc@1c0f000: 0, mmc@1c10000: 2, mmc@1c11000: 1

其实uboot打印的序号、地址与规格书是有出入的,这里不做深入研究,与我们现在的问题解决关系不大。ps之前就是以为有关系,花了好大力气研究这里,白白浪费时间 -_-!
orangepi pc plus mmc接口硬件设计如下
sd/mmc0→tf卡
sd/mmc1→wifi
sd/mmc2→emmc
part是对应的存储介质内部的分区。
由上可知前面的打印意思是mmc 1设备的分区1无法使用。

三、问题解决

我们先从上面的疑点1入手~

3.1 解疑点1

如下是采用可视化分区工具gparted查看装有系统tf卡的分区情况
这工具挺好用的,适合小白可通过sudo apt install gparted安装。
在这里插入图片描述
tf卡只做了一个分区sdb1,并且格式化为ext4,分区1里面存放的就是启动系统。
分区1
其中boot里面存放的就是linux kernel编译好的镜像,还有启动参数boot.scr。
boot启动参数
那么有人会问uboot存放在哪呢?
其实是是放在tf卡前面未分配的4MB里面,这里不细说。
在这里插入图片描述
额。。。以上有点扯远了。
其实问题就出在分区1格式化为ext4!
因为前面uboot的fat_set_blk_dev函数会检查分区格式是否为FAT/FAT32。虽然h3启动对分区格式无要求,能正常加载到想要的数据就行,但不正确的格式影响uboot环境变量加载、保存。
解决方法查看我另外一篇文章。

3.2 解疑点2

以上就算格式化正确了,还是无法解决环境变量问题。
因这个版本uboot存在问题,默认是从mmc 1分区1加载、保存环境变量。
根据前面的推断mmc 1并非tf卡,在加上打印信息与Datasheet有出入,做如下推断:
打印的mmc 1 对应地址是mmc@1c11000,而该地址在Datasheet对应的是mmc2,实际硬件接的emmc。也就是不管插不插卡,默认都是从emmc加载、保存环境变量。
要做的就是修改从tf卡加载、保存环境变量。
下面这个函数的CONFIG_ENV_FAT_DEVICE_AND_PART,就是导致默认从mmc1加载环境变量的。

part = blk_get_device_part_str(CONFIG_ENV_FAT_INTERFACE,
				CONFIG_ENV_FAT_DEVICE_AND_PART,
				&dev_desc, &info, 1);

该宏定义在:include/generated/autoconf.h

#define CONFIG_ENV_FAT_DEVICE_AND_PART "1:auto"

是env/Kconfig通过MMC_SUNXI_SLOT_EXTRA的不同值自动生成的。

config ENV_FAT_DEVICE_AND_PART
	string "Device and partition for where to store the environemt in FAT"
	depends on ENV_IS_IN_FAT
	default "0:1" if TI_COMMON_CMD_OPTIONS
	default "0:auto" if ARCH_ZYNQMP
	default "0:auto" if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA = -1
	default "1:auto" if ARCH_SUNXI && MMC_SUNXI_SLOT_EXTRA != -1
	default "0" if ARCH_AT91

而MMC_SUNXI_SLOT_EXTRA则定义在configs/orangepi_pc_plus_defconfig

CONFIG_MMC_SUNXI_SLOT_EXTRA=2

这定义估计是单板支持2个启动mmc设备。
查看orangepi pc(无emmc)的配置文件orangepi_pc_defconfig,则没有该参数。采用该配置文件编译之后CONFIG_ENV_FAT_DEVICE_AND_PART如下:

#define CONFIG_ENV_FAT_DEVICE_AND_PART "0:auto"

试着把orangepi_pc_plus_defconfig的CONFIG_MMC_SUNXI_SLOT_EXTRA屏蔽掉,
编译之后值同上。
最终效果见这两篇博文
香橙派orangepi pc plus h3 启动tf卡制作

  • 5
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值