Uboot 下识别带 CD-ROM 的 U盘报 *irq: data 错误

1
2
版本
uboot:u-boot 2018.07

问题描述

带 CD-ROM 的U盘、硬盘在 uboot 下执行 usb star t报 *irq: data 刷屏打印。

问题原因

1、通过与 uboot 2010、u-boot 2016 对比发现并没有该问题。

2、加打印追踪函数,发现问题点在 disk/part_dos.c 下的 static int part_test_dos(struct blk_desc *dev_desc) 函数。

3、考虑到以往版本没问题,于是查看该文件的修改记录,发现了这笔提交。

1
2
3
4
5
6
7
8
9
10
@@ -90,7 +90,7 @@ static int test_block_type(unsigned char *buffer)
static int part_test_dos(struct blk_desc *dev_desc)
{
#ifndef CONFIG_SPL_BUILD
- ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, mbr, dev_desc->blksz);
+ ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, mbr, 1);

if (blk_dread(dev_desc, 0, 1, (ulong *)mbr) != 1)
return -1;

这笔修改是觉得为 mbr 申请一个 legacy_mbr * dev_desc->blksz的内存空间太浪费了,申请一个 legacy_mbr 大小就够了。

4、checkout 这个修改,发现问题解决。

5、该笔提交与内存相关,继续追踪使用 mbr 的函数。

blk_dread(dev_desc, 0, 1, (ulong *)mbr) –> blkcache_read(block_dev->if_type, block_dev->devnum, start, blkcnt, block_dev->blksz, buffer) –> memcpy(buffer, src, blksz * blkcnt);

最后确定问题是因为 blkcache_read 内的 memcpy 越界了。

6、结合问题是发生在usb start 识别U盘阶段,在函数 part_test_dos 内部。我们认为识别存储类设备时,需要读取并解析其分区表,而分区表大小与设备的 sector 相关。sector即是block size,普通U盘 sector 大小是 512 byte,移动硬盘可能存在 4096 byte,对于 CD-ROM设备则是 2048 byte。

7、对结构体 legacy_mbr 大小的计算为 512 byte。

1
2
3
4
5
6
7
8
9
10

/* based on linux/include/genhd.h */
struct partition {
u8 boot_ind; /* 0x80 - active */
u8 head; /* starting head */
u8 sector; /* starting sector */
__le16 unknown;
struct partition partition_record[4];
__le16 signature;
} __packed legacy_mbr;

8、综上,src 对应的是 CD-ROM 的分区表,buffer 是 mbr,blksz为 2048,memcpy 自然会拷贝越界了。

1
2
3
4
5
6
7
8
9
10
11
int blkcache_read(int iftype, int devnum,
lbaint_t start, lbaint_t blkcnt,
unsigned long blksz, void *buffer)
{
struct block_cache_node *node = cache_find(iftype, devnum, start,
blkcnt, blksz);
if (node) {
const char *src = node->cache + (start - node->start) * blksz;
memcpy(buffer, src, blksz * blkcnt);
debug("hit: start " LBAF ", count " LBAFU "\n",
start, blkcnt);

解决方法

1、使用设备的 sector 大小确定函数 part_test_dos() 中 mbr 的大小,防止内存拷贝越界。

2、为了不浪费内存资源,我们决定这样修改。

1
2
3
4
5
6
7
8
static int part_test_dos(struct blk_desc *dev_desc)
{
#ifndef CONFIG_SPL_BUILD
- ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, mbr, 1);
+ ALLOC_CACHE_ALIGN_BUFFER(legacy_mbr, mbr, (dev_desc->blksz / sizeof(legacy_mbr)));

if (blk_dread(dev_desc, 0, 1, (ulong *)mbr) != 1)
return -1;

3、后续通过 sector 大小为 512 byte 到 8192 byte 的虚拟U盘及 4096 byte 的移动硬盘验证,均正常识别,无 *irq: data 的刷屏打印了。


Uboot 下识别带 CD-ROM 的 U盘报 *irq: data 错误
http://xxxdk.xyz/xxx/2019/07/Uboot下识别带CD-ROM-U盘报-irq-data错误/
作者
sni
发布于
2019年7月21日
许可协议