迅为4412修改uboot以支持4G以上的分区

修改uboot以支持4G以上的分区

接到任务需要:需要对itop4412的开发板给根目录分配4G以上的空间。因为uboot默认使不能分配4G以上分区的,因此需要修改源码。

祭出“百度大法”,找到了下面的博客:

博客地址:https://www.cnblogs.com/stay-foolish1984/p/10489625.html。
关键内容:

/common/Cmd_mmc_fdisk.c里面的 unsigned int calc_unit(unsigned int length,
SDInfo sdInfo),length定义的是unsigned int,是32bit的。但是调用的时候输入是unsigned long
long,是64bit的。block_offset = calc_unit((unsigned long
long)simple_strtoul(argv[3], NULL, 0)10241024,
sdInfo);所以这个过程中,丢了高位置信息,改掉这个bug,重新编译uboot。

总结一句话就是,数据的大小超出了数据的可允许范围,导致数据被截断。例如一个char类型的数据是8位 ,可表示255也就是十六进制的0xff。当表示257的时候,那么则为十六进制的0x101。但是char最多存储8位,因此高位的0x101中的1被丢弃(二进制的8位就是十六进制的2位)则只剩下了0x01 。也就是十进制的1。
如何快速计算一个数被截断后剩余多少呢?将这个数与它的数据类型所表示的最大的数+1取余即可。例如:char最大表示255,+1 是256。257%256取余的结果为1。
同理,32位的int类型的数X则是X %(2^32 + 1)

按照博客中的提示,将

unsigned int calc_unit(unsigned int length, SDInfo sdInfo),

改为

unsigned int calc_unit(unsigned long long length, SDInfo sdInfo),

重新编译uboot,烧录后重新进行分区。5G分区成功,事情竟然如此顺利?然后修改system.img镜像的分区大小也为5G。开始烧录。

然而事情并不简单

虽然分区成功了,但是烧录的时候依然报错:

Invalid Volume Size! Image is bigger than partition size

不应该啊,分区已经成功修改了,莫非是镜像的分区设置的太大了?于是修改镜像大小为4.9G重新烧录,依然如此。此时懒得再去百度了,自己解决吧!
首先利用shell命令

find . -type f |xargs grep "Invalid Volume Size! Image is bigger than partition size"

查找这个提示出现在哪个文件中,我们去看他具体的代码内容。据此,我们找到了common/decompress_ext4.c这个文件,打开文件中再搜索报错的字符串:
在这里插入图片描述

根据代码判断这里应该是用 分区的大小 / 文件的块大小 得到分区的block数, 再去对比 镜像的block总块数,如果分区的block总数小于镜像的block总数,说明分区不合法。Parti_size表示的分区的大小,我们看下这句代码所在的函数
在这里插入图片描述

parti_size的类型也是unsigned int,那传入的尺寸如果大于unsigned int的数据范围一样会被截断,导致后面的判断结果错误。于是我们改为如下这样:

在这里插入图片描述

同时别忘了修改include/decompress_ext4.h头文件中相应的函数声明。
再次编译,然后重新烧录。问题依旧!!!
莫非调用check_compress_ext方法的时候传入的parti_size已经是被截断的unsigned int的类型了?我们再用上面查找错误提示的的方法去查找哪个文件调用了check_compress_ext

在这里插入图片描述

打开此文件并查找check_compress

在这里插入图片描述

传入的参数为ptn->length;那我们再看看ptn这个结构体是如何定义的。往上找,看看ptn是如何赋值的。

在这里插入图片描述

ptn是直接通过函数传递进来的,而且pth的结构体定义是struct fastboot_ptentry
我们再使用find配合grep的方法找到这个结构体是在include/fastboot.h中定义的:

在这里插入图片描述

成员length的类型同样是unsigned int。修改如下:

在这里插入图片描述

先编译uboot测试。问题依旧,果然不是那么简单就可以解决的。根据我的推测,uboot应该是先读取分区尺寸大小的信息,然后保存在fastboot_ptentry结构体中,那么是不是有可能在把分区大小信息赋值到结构体中的length变量的时候,就已经被截断了呢?
看来有点棘手,夜已深,但是问题不解决哪能安心睡觉呢?简单洗漱一下裹上我的小被几继续。
接下来看看都有哪些文件调用了fastboot_ptentry结构体,并给他赋值了吧。

在这里插入图片描述

还好,全部都在cmd_fastboot.c中,而不是分散在多个文件中,这就方便很多了。
然后我挨个查看了使用了pth结构体的函数,然后发现了设置分区参数的函数
set_partition_table
但是观察代码发现,这个是根据环境变量来赋值分区信息的,而我们的分区信息是保存在了mmc里面。所以基本判断不是这个函数。

柳暗花明

线索中断了,莫非我的判断不对?
这个函数从环境变量读取分区信息的,那么调用这个函数的地方会不会也有从mmc读取的步骤呢?

在这里插入图片描述

果然,在调用这个函数的附近,发现了set_partition_table_sdmmc()
我们进入这个函数,原来也在cmd_fastboot.c里面(而且就在set_partition_table这个函数下面…)
一行一行的看代码,找到了希望:

在这里插入图片描述

count和后面的常量都是unsigned int类型,这里就是一个比较容易出错的地方,虽然我们之前已经把length成员的变量修改为unsigned long long,但是在c语言中,两个int类型的数据相乘,结果也会按照int类型保存。这样如果结果大于了int的范围,那么依然会被截断!!(起码我所使用的交叉编译器如此)。
如何避免呢?把其中一个变量类型强转为unsigned long long即可,这样编译器会自动转换两个操作数都为unsigned long long类型,结果自然也就是unsigned long long喽。

在这里插入图片描述

编译,烧录。成功!!!
关机睡觉!!!

后记:

虽然在文中写的解决过程是一步步的进行推导,然而在实际的解决过程中并没有这么的逻辑清晰,也远比文中写的复杂很多。因为我不熟悉uboot(第一次编译),也不常烧录嵌入式系统,所以对此流程不甚了解。尝试不少错误的线索,或者同时在多个线索上推导,因此过程也是十分无聊和枯燥的。前后总共耗费了两个晚上才解决。

现在的过程仅仅是解决后的复盘,省去了很多的弯路。其实或许也有更简单的解决办法,例如单纯的注释掉判断部分的代码,这样是不是也能正常烧录呢?我并没有这么做,因为这样出现问题就忽略问题的办法个人不推荐。

那么如果一开始就从uboot的执行流程顺序判断,是不是能更快找到问题所在呢?或许吧,但是因为对uboot不熟悉,因此可能熟悉整个流程也需要消耗更多的时间呢?

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值